用于同步迭代器的等待 [英] Using for await...of with synchronous iterables

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

问题描述

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.

以下代码在一个同步可迭代对象(一个promise数组)上进行迭代.似乎阻碍了每项诺言的实现.

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.)

那么为什么在语言中支持此功能?继续草率的诺言语义.

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

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

我认为我们应该退回到Symbol.iterator,因为我们当前 承诺语义是关于允许将同步内容用作 异步的东西.您可能将其称为草率".它遵循 @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的链接"语义与此有关.您可以返回一个 从.then或标量值保证;全部都是一样.你打电话 Promise.resolve不是将某些内容包装在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).

异步迭代器和生成器应该以相同的方式工作.就像你一样 可以等待偶然地不是一个承诺,合理的价值 用户期望能够在异步中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.

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

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