近日再做一些模块化相关的工作,遇到这样一个问题
模块A负责处理数据层面的一些逻辑,模块B负责处理视图层面的一些逻辑
现在A要调用B的方法,做一些视图逻辑的处理,之后要再B调用回A的方法,处理一些数据逻辑,最后再回到B,继续处理视图逻辑,听起来很绕对吧!是的!
一般碰到这种调用来又调用去的东西,我们很容易想到就是import,管他三七二十一,我直接导,导不出来再想办法!
但是如今这个场景,兄弟们如果直接导,会导致模块间的循环引用,代码会报错,那怎么办?
我就想到了写一个CallBack回调,按照事情发生的顺序,一步一步执行下来,下面是我的思路
- A模块调用B模块的方法,把整个事件的主导交给B,并把回调方法交给B
- B先处理视图逻辑,处理的差不多了,调用A给的回调(改为同步)
- 等到A的回调做完了,回来继续执行B
听起来还是很绕,不如直接看代码
【模块A】
let params = { multiple, small, big }
//scanConfig为B模块引入的对象
//renderScanPic为A模块写的回调方法
that.scanConfig.scanUploadViewBuilder( params, (data)=>that.renderScanPic(data) )
renderScanPic(data){
return new Promise(async (resolve,reject)=>{
for(const o of data){
let result = o
this.dataAndView_addData('img',result)
const config = {
src: o.thumb_url,
notes: null,
fileName,
status:0
}
await this.renderSinglePic(config)
}
resolve(true)
})
}
【模块B】
//模块B scanConfig提供的方法 scanUploadBuilder
//可以看出来这里确实是一些视图层的代码
//同时,接收两个参数,也是A传过来的,一个是一些普通参数,一个是A的回调
scanUploadViewBuilder(params, getDataAndRenderCallBack) {
const that = this
const { multiple, small, big } = {...params}
let timestamp = new Date().getTime()
params = `?multiple=${multiple}&small=[${small}]&big=[${big}]×tamp=${timestamp}`
const H5_upload_src = that.uploadUrl + params
let QRCodeContainer = $(`<div class="QRCode-container QRCodeContainer"></div>`)
let QRCodeContent = $(`<div class="QRCodeContent"></div>`)
let QRCodeContentTop = $(`<div class="phoneUploadStyle QRCodeContentTop"></div>`)
let QRCodeContentBottom = $(`<div class="QRCodeContentBottom">
<div style="margin-top:-10px;" id="qrCode"></div>
<div class="QRCodeContentBottomTips">传图期间请勿关闭此二维码</div>
</div>`)
let QRCodeContentTopText = '<span>手机扫码传图片(不支持文件上传)</span>'
let QRCodeContentTopIcon = $(`<svg
t="1687167723133"
viewBox="0 0 1024 1024"
width="22"
height="22"
style="float: right;cursor: pointer;">
<path d="M860.4 64H163.6c-50.9 0-92.2 41.3-92.2 92.2v711.5c0 50.9 41.3 92.2 92.2 92.2h696.8c50.9 0 92.2-41.3 92.2-92.2V156.2c0-50.9-41.3-92.2-92.2-92.2zM721.9 642.1c24.4 24.4 24.4 64 0 88.4-24.4 24.4-64 24.4-88.4 0L512 609 390.5 730.5c-24.4 24.4-64 24.4-88.4 0-24.4-24.4-24.4-64 0-88.4l121.5-121.5-121.4-121.5c-24.4-24.4-24.4-64 0-88.4 24.4-24.4 64-24.4 88.4 0L512 432.2l121.5-121.5c24.4-24.4 64-24.4 88.4 0 24.4 24.4 24.4 64 0 88.4L600.4 520.6l121.5 121.5z" fill="#626262"></path>
</svg>`)
QRCodeContentTopIcon.on('click', that.removeQRCodeContainer_upload.bind(this))
$('body').append(
QRCodeContainer.append(
QRCodeContent.append(
QRCodeContentTop.append(
QRCodeContentTopText, QRCodeContentTopIcon
)
, QRCodeContentBottom
)
)
)
$('#qrCode').qrcode(H5_upload_src)
/呐呐呐
/这里我又调用了B的另一个方法,同时把A的回调拿过去用了
/
that.timePolling_upload(timestamp, getDataAndRenderCallBack)
}
removeQRCodeContainer_upload() {
$('.QRCode-container').remove()
clearInterval(this.clear)
}
//没错,就是它最终拿到A的回调
timePolling_upload(timestamp, getDataAndRenderCallBack){
const that = this
let accpetData = []
this.clear = setInterval(() => {
$.ajax({
type: 'get',
dataType: 'json',
url: that.getUrl + '?get_image=1&unique_id=' + timestamp,
async success(res) {
if (res.code == 1) {
if(JSON.stringify(accpetData) != JSON.stringify(res.data)){
accpetData = res.data
}else{
这里是使用A回调的地方,绕了一大圈 终于到了
const resultData = that.transformFormatData(accpetData)
//然后就等,getDataAndRenderCallBack得return一个promise
await getDataAndRenderCallBack(resultData)
//等完了,继续执行视图
that.removeQRCodeContainer_upload()
}
}
}
})
}, 5000)
}
模块B比较啰嗦,大家看我写注释的地方就好了,那么,这篇文章的精髓在哪里,我个人认为,是在A模块那里,(data)=>that.renderScanPic(data),就这里,相当的精髓
一开始我的写法其实不是这样的,我直接that.renderScanPic,没加箭头函数,(好吧一开始甚至还写成that.renderScanPic(data),但这样不行,因为给了括号,他会认为我需要在此时执行这个方法,并把返回值传给模块B,这样是不对滴)。
那么为什么突然要加个箭头函数呢?如果不加,我的renderScanPic会丢失this的指向,我在这个A模块的方法中把这个this打印出来,他既不指向A,也不指向B,大家猜猜,他会指向什么,他居然指向undefined,之前我也写过一篇关于this指向的文章,但像当前这种绕来绕去的场景,确实也是没有考虑到。
那么又继续到我的推测环节了,为什么A调用B调用A的回调,this的指向会变成undefined?
首先,依照我的推理,this至少也得指向B吧?因为B调用A的回调,也就是A的方法会进到B里面,那么这时候的作用域,按道理得是B,但目前是undefiend,只能让懂得兄弟评论区解答一下了,后续我也会再补充一下这个问题的答案(我会亲自去尝试一下),暂且就在这里收尾吧!