使用 for await...of 同步迭代 [英] Using for await...of with synchronous iterables

查看:20
本文介绍了使用 for await...of 同步迭代的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

MDN for await...of 有两个用例:

MDN says for await...of has two use-cases:

for await...of 语句创建一个循环迭代异步可迭代对象以及同步可迭代对象,...

The for await...of statement creates a loop iterating over async iterable objects as well as on sync iterables,...

我之前知道前者:使用 Symbol.asyncIterator 的异步迭代.但我现在对后者感兴趣:同步迭代.

I was previously aware of the former: async iterables using Symbol.asyncIterator. But I am now interested in the latter: synchronous iterables.

以下代码迭代一个同步可迭代对象 - 一个承诺数组.它似乎阻碍了每个承诺的实现.

The following code iterates over a synchronous iterable - an array of promises. It appears to block progess on the fulfilment of each 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)

根据下面显示的逻辑,这种行为似乎类似于依次等待每个承诺.这个说法正确吗?

The behavior appears to be akin to awaiting each promise in-turn, per the logic shown below. Is this assertion correct?

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.allPromise.allSettled 避免了,我觉得这很奇怪该语言将明确支持模式.

I ask because this pattern of code has an implicit rejection wire-up pitfall that Promise.all and Promise.allSettled avoid, and it seems strange to me that this pattern would be explicitly supported by the language.

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)

推荐答案

是的,很奇怪,你不应该这样做.不要迭代承诺数组,它会导致您提到的未处理拒绝问题.(另见这个更具体的解释.)

Yes, it is strange, and you should not do this. Don't iterate arrays of promises, it leads exactly to the unhandled-rejections problem you mentioned. (See also this more specific explanation.)

那么为什么该语言支持此功能?继续草率的 promise 语义.

So why is this supported in the language? To continue with the sloppy promise semantics.

您可以在这篇评论中找到确切的推理讨论提案的这一部分的问题:

我认为我们应该回到 Symbol.iterator 因为我们当前的Promise 语义都是关于允许将同步的东西用作异步的东西.你可以称之为草率".它跟随@groundwater 上面的逻辑,但我只想更详细地说明相似之处.

I think we should fall back to Symbol.iterator because our current Promise semantics are all about allowing sync things to be used as async things. You might call this "sloppiness". It follows @groundwater's logic above, but I just want to spell out the parallels in more detail.

.then 的链接"语义就是关于这个的.你可以返回一个Promise 来自 .then 或一个标量值;全部都是一样.你打电话Promise.resolve 不是将某些东西包装在 Promise 中,而是进行强制转换Promise 的一些东西——当你有一个异步值时某事或其他.

The "chaining" semantics of .then are all about this. You can return a Promise from .then or a scalar value; it's all the same. You call Promise.resolve not to wrap something in a Promise, but to cast something to a Promise--get an asynchronous value when you have something-or-other.

asyncawait 的语义也都是关于草率的.您可以在异步函数中的任何非 Promise 表达式上使用 await一切都很好,完全一样,除了你屈服控制作业队列.同样,您可以防御性地"放置 async只要你await结果,你想要什么都可以.如果你有一个返回 Promise 的函数——无论如何!你可以把它变成async 功能,并且从用户的角度来看,没有任何变化(即使如果,从技术上讲,你得到一个不同的 Promise 对象).

The semantics of async and await are all about being sloppy as well. You can slap await on any non-Promise expression in an async function and everything works fine, exactly the same way, except that you yield control to the job queue. Similarly, you can "defensively" put async around whatever you want, as long as you await the result. If you have a function that returns a Promise--whatever! you can make that an async function, and, from a user perspective, nothing changes (even if, technically, you get a different Promise object out).

异步迭代器和生成器应该以相同的方式工作.就像你一样可以等待一个意外地不是 Promise 的值,一个合理的用户希望能够在异步中yield* 同步迭代器发电机.for await 循环应该类似地正常工作",如果用户以这种方式防御性地标记一个循环,认为它们可能是获取异步迭代器.

Async iterators and generators should work the same way. Just like you can await a value that, accidentally, wasn't a Promise, a reasonable user would expect to be able to yield* a sync iterator within an async generator. for await loops should similarly "just work" if a user defensively marks a loop that way, thinking that they maybe might be getting an async iterator.

我认为打破所有这些相似之处将是一件大事.它会使异步迭代器不符合人体工程学.让我们接下来讨论这个时间异步生成器/迭代器被提上了 TC39 的议程.

I think it would be a big deal to break all of these parallels. It would make async iterators less ergonomic. Let's discuss this the next time async generators/iterators come up on the agenda at TC39.

这篇关于使用 for await...of 同步迭代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆