在一个平平无奇的上午,测试突然反馈测得好好的,弹窗就打不开了,刷新完页面就好了。啥?这是发生了什么?我的弹窗去哪儿了呢?由于测试反馈出现弹窗打不开的中途有人部署了前端代码,我一开始怀疑难道是静态资源出了问题?于是开启漫长的找bug之旅...
1.不是静态资源的问题
看了下弹窗的引入和调用逻辑,并没有异步加载,所以排除静态资源没正确加载,那会是点击按钮打开弹窗的逻辑有问题?
2.弹窗打开逻辑
弹窗打开逻辑如下:一个点击按钮调用两个接口,接口调用成功,打开弹窗
function promise1() {
return this.$http.post('url1', {})
.then(() => {
// 初始化弹窗展示需要的参数
this.dialogInfo = xxx
})
.catch(() => {})
}
function promise2() {
return this.$http.post('url2', {})
.then(() => {})
}
function handleClick() {
Promise.all([promise1, promise2])
.then(() => {
this.showDialog = true;
})
.catch((err) => {
console.log(err)
})
}
如上面伪代码,简单几行,也没看出什么问题。想着先复现一下?点了几次,未果。。。
3. 问题复现出来了!!!
正当我一筹莫展的时候,同事大佬喊我,复现出来了!!!
slow 3G 下,他复现了我的bug,此处为大佬疯狂打call!!!
经排查,我们发现了一个问题:在vue-devtools中,showDialog已经变成了true,但是弹窗展示需要的参数dialogInfo无值。所以我们猜测接口url1发生过报错,并且全局给showDialog的赋值语句只有一处,代码不会骗人,毫无疑问,程序一定是执行了Promise.all().then,不是说其中一个Promise发生了reject,Promise.all都会触发catch吗?这是为什么呢?此刻,人有点麻了...
4. 试下我们的猜想
接口报错,那可以让它超时,于是给了个很慢的下载速度,两个接口都超时了,发现showDialog为false,赋值逻辑并没有触发...难道只是第一个接口的锅?于是注释掉promise2,仅留下promise1再次尝试
果然,在promise1超时后,问题复现了,showDialog为true,且由于dialogInfo没有正确的值,控制台出现了弹窗的报错...这是为什么呢?
5. 难道是.catch的锅?
来做个尝试
const promise1 = new Promise((resolve, reject) => {
resolve('success')
}).then((res) => {
return res
})
const promise2 = new Promise((resolve, reject) => {
reject('err')
}.then((res) => {
return res
})
Promise.all([promise1, promise2])
.then(res => {
console.log('promise-all-success:' + res)
})
.catch(err => {
console.log('promise-all-err:' + err)
})
// 输出:promise-all-err:err
const promise1 = new Promise((resolve, reject) => {
resolve('success')
}).then((res) => {
return res
})
const promise2 = new Promise((resolve, reject) => {
reject('err')
}).then((res) => {
return res
}).catch((err) => {
return err
})
Promise.all([promise1, promise2])
.then(res => {
console.log('promise-all-success:' + res)
})
.catch(err => {
console.log('promise-all-err:' + err)
})
// 输出:promise-all-success:success,err
const promise1 = new Promise((resolve, reject) => {
resolve('success')
}).then((res) => {
return res
})
const promise2 = new Promise((resolve, reject) => {
reject('err')
}).then((res) => {
return res
}, (err) => {
return err
})
Promise.all([promise1, promise2])
.then(res => {
console.log('promise-all-success:' + res)
})
.catch(err => {
console.log('promise-all-err:' + err)
})
// 输出:promise-all-success:success,err
如上尝试,我们发现,在单个Promise中处理了错误,Promise.all将不会再次走catch的逻辑
最后再贴一段通义灵码给出的解释:
附上Promise.all的官方文档: developer.mozilla.org/zh-CN/docs/…