一文详解如何有效的处理Promise并发
前言
如上图所示的代码,相信大家在平时的开发中肯定用到不少,我们可以进行优化,使得只用短短一半的时间就可以完成。 在上面的函数中,我们等待用户信息请求完成后再请求详情信息。但这两个函数之间并没有任何关联,所以我们可以同时触发两个请求,并同时等待完成。那么,我们有多少种方式来实现呢?你真的可以处理好Promise
的并发么?接下来,我们进入正题。
Promise.all
如何实现
Promise.all 大家应该是比较熟悉的,Promise.all
方法接收一个promise
的iterable
类型,如果所有传入的promise
都变成完成状态,Promise.all
返回的Promise异步的变为完成。如果传入的promise
中有一个失败(rejected
),Promise.all
将失败的结果给失败状态的回调函数,而不管其他promise
是否完成。 我们可以如下实现刚才的代码
async function init() {
const [user, info] = await Promise.all([
getUser(),
getInfo()
])
console.log('init', user, info)
}
现在这种方式,如果我们之前每个请求都需要1秒,一共需要2秒,那么现在两个同时执行只需要1秒就完成了!但是这样也有一个问题:我们并没有考虑报错问题。你可能会认为,这个很简单,把代码放在一个try...cahtch
中不就可以了,就像这样:
async function init() {
try {
const [user, info] = await Promise.all([
getUser(),
getInfo()
])
console.log('init ==== ', user, info)
} catch(err) {
console.log('err', err);
}
}
但是,这样的话会有一个问题,就像这样:
function getUser() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('user reject')
}, 500);
})
}
function getInfo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('info reject')
}, 1000);
})
}
// 输出 err user reject
由于getUser
优先完成并出现错误,此时触发了catch
,而当getInfo
再次完成并出现错误时,将不会触发catch
。因为catch
代码已经运行,函数已经完成。 那么,要怎么做呢?接下来,我们就讲讲应该如何处理报错问题。
如何处理报错
解决方式是,给Promise.all
中的每个函数加上catch
,如下:
function handle(err) {
console.log('err', err)
}
function onReject(err) {
handle(err);
return new Error(err);
}
async function init() {
const [user, info] = await Promise.all([
getUser().catch(onReject),
getInfo().catch(onReject)
])
console.log('init', user instanceof Error, info instanceof Error) // init true true
}
这样,我们在onReject
函数中处理错误,并返回这个错误。所以现在我们生成的user
和info
要么是Error
要么是我们期望的效果,而Error
我们可以用instanceof
检查它。
Promise.allSettled
解决并发我们还可以使用 Promise.allSettled ,我们会得到一个包含每个Promise
结果的值或错误信息。
如何实现
接下来,我们来使用一下,代码如下:
async function init() {
const [userStatus, infoStatus] = await Promise.allSettled([
getUser(),
getInfo()
])
console.log('info', userStatus, infoStatus)
}
现在,我们可以得到这样的数据:
结果对象有3个属性:
- status:
fulfilled
或rejected
- value: 仅在
status
为fulfilled
时出现,为Promise
为resolve
返回的值 - reason: 仅在
status
为rejected
时出现,为Promise
被reject
时返回的值
因此,我们可以读取到每个Promise
的状态,并单独处理每个错误而不会遗漏任何的信息。
最后两个技巧
Promise.race
Promise.race方法可接受一个可迭代的promise
返回一个promise
,一旦迭代器中某个promise
解决或拒绝,返回的promise
就会resolve
或reject
。
我们可以这样实现一个简单的超时功能,代码如下:
function getUser() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('user resolve')
}, 5100);
})
}
async function init() {
// Race to see which Promise completes first
const racePromise = Promise.race([
getUser(),
new Promise((resolve, reject) =>
// Time out after 5 seconds
setTimeout(() => reject(new Error('Timeout')), 5000)
)
])
try {
const result = await racePromise
console.log('result', result)
} catch (err) {
console.log('err', err)
// Timed out!
}
}
注意,通常情况下,如果有超时,那么你需要尽量的取消未完成的待处理任务。
另外,最好还是处理所有promise
的reject
:
const racePromise = Promise.race([
getUser().catch(onReject),
// xxx
])
Promise.any
Promise.any 等待任何一个promise
成功则为成功,只有全部的promise
都被reject
,才会返回reject
。通常我们可以使用Promise.any
来实现,当一个promise
先完成后,取消其他的promise
,不过要注意的是,我们并不总是同时要处理多个数据,只是因为我们可以做到,所以要谨慎的使用它。
通常,我们不想出现未被处理的reject
,所以,我们应该这样写:
const anyPromise = Promise.any([
getUser().catch(onReject),
getInfo().catch(onReject)
])
总结
前面我们已经介绍了在使用promise
处理并发问题时,应该如何的处理promise
的reject
。但是也需要注意:过度的并发会导致网络抖动、磁盘抖动或其他问题,虽然可以,但并不是一定要这样做,有时使用async await
也可以使代码更容易理解和维护,所以,在使用之前我们更需要考虑是否需要。
- 参考文章:www.builder.io/blog/promis…
以上就是一文详解如何有效的处理Promise并发的详细内容,更多关于有效处理Promise并发的资料请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341