MDN says https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of for await...of
有两个用例:
The for await...of
语句创建一个循环迭代 async
可迭代对象以及同步可迭代对象,...
我之前知道前者:使用异步迭代Symbol.asyncIterator
。但我现在对后者感兴趣:同步迭代。
以下代码迭代同步可迭代对象 - 一个 Promise 数组。它似乎阻碍了每项承诺的履行进程。
async function asyncFunction() {
try {
const happy = new Promise((resolve)=>setTimeout(()=>resolve('happy'), 1000))
const sad = new Promise((_,reject)=>setTimeout(()=>reject('sad')))
const promises = [happy, sad]
for await(const item of promises) {
console.log(item)
}
} catch (err) {
console.log(`an error occurred:`, err)
}
}
asyncFunction() // "happy, an error occurred: sad" (printed in quick succession, after about 5 seconds)
根据下面所示的逻辑,该行为似乎类似于依次等待每个承诺。这个说法正确吗?
async function asyncFunction() {
try {
const happy = new Promise((resolve)=>setTimeout(()=>resolve('happy'), 1000))
const sad = new Promise((_,reject)=>setTimeout(()=>reject('sad')))
const promises = [happy, sad]
for(let p of promises) {
const item = await p
console.log(item)
}
} catch (err) {
console.log(`an error occurred:`, err)
}
}
asyncFunction() // "happy, an error occurred: sad" (printed in quick succession, after about 5 seconds)
我问这个问题是因为这种代码模式有一个隐式拒绝接线陷阱Promise.all
and Promise.allSettled
避免,对我来说奇怪的是该语言明确支持这种模式。
window.addEventListener('unhandledrejection', () => {
console.log('unhandled rejection; `sad` was not being awaited at the time it rejected')
})
async function asyncFunction() {
try {
const happy = new Promise((resolve)=>setTimeout(()=>resolve('success'), 1000))
const sad = new Promise((_,reject)=>setTimeout(()=>reject('failure')))
const promises = [happy, sad]
for(let p of promises) {
const item = await p
console.log(item)
}
} catch (err) {
console.log(`an error occurred:`, err)
}
}
asyncFunction() // "unhandled rejection; `sad` was not being awaited at the time it rejected" (after about zero seconds), and then "happy, an error occurred: sad" (printed in quick succession, after about 5 seconds)
是的,这很奇怪,你不应该这样做。不要重复一系列的承诺,它会导致正是针对您提到的未处理的拒绝问题 https://stackoverflow.com/q/46889290/1048572。 (也可以看看这个更具体的解释 https://stackoverflow.com/a/59695815/10485.)
那么为什么该语言支持这一点呢?继续草率的承诺语义。
您可以在中找到确切的推理讨论提案这一部分的问题的评论 https://github.com/tc39/proposal-async-iteration/issues/12#issuecomment-246403264:
我认为我们应该回到Symbol.iterator
因为我们当前的
Promise 语义就是允许同步事物被用作
异步的事情。你可以称之为“草率”。它跟随@groundwater上面的逻辑 https://github.com/tc39/proposal-async-iteration/issues/12#issuecomment-157209898,
但我只是想更详细地阐明两者的相似之处。
“链接”语义.then
都是关于这个的。您可以返回一个
承诺来自.then
或标量值;全部都是一样。你打电话Promise.resolve
不是将某些东西包装在 Promise 中,而是进行投射
Promise 的某物——当你有时获取一个异步值
某事或其他。
的语义async
and await
都是关于马虎的。
你可以打巴掌await
在异步函数中的任何非 Promise 表达式上
一切都工作正常,完全一样的方式,除了你屈服
控制作业队列。同样,你可以“防御性”地放置async
围绕着你想要的一切,只要你await
结果。如果你有
一个返回 Promise 的函数——无论如何!你可以把它变成async
功能,并且从用户的角度来看,没有任何变化(甚至
如果从技术上讲,你得到了一个不同的 Promise 对象)。
异步迭代器和生成器应该以相同的方式工作。就像你一样
可以等待一个意外地不是 Promise 的值,一个合理的值
用户希望能够yield*
异步中的同步迭代器
发电机。for await
循环应该类似地“正常工作”,如果用户
以这种方式防御性地标记一个循环,认为他们可能会
获取异步迭代器。
我认为打破所有这些相似之处将是一件大事。它
会使异步迭代器不太符合人体工程学。我们接下来讨论这个
时间异步生成器/迭代器出现在 TC39 的议程上。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)