异步生成器:产生被拒绝的承诺 [英] Async Generator: Yielding a rejected promise

查看:73
本文介绍了异步生成器:产生被拒绝的承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在与异步生成器一起玩耍,以尝试制作一个承诺排序"生成器,该生成器接受一组承诺并以它们解决或拒绝的顺序逐一产生承诺.像这样:

I've been playing around with async generators in an attempt to make a "promise ordering" generator which takes an array of promises and yields out promises one by one in the order they resolve or reject. So something like:

async function* orderProms(prom_arr) {

    // Make a copy so the splices don't mess it up.
    const proms = [...prom_arr];

    while (proms.length) {
        // Tag each promise with it's index, so that we can remove it for the next loop.
        const {prom, index} = await Promise.race(proms.map((prom, index) => prom.then(
            () => ({prom, index}),
            () => ({prom, index})
        )));

        proms.splice(index, 1);
        yield prom;
    }
}

使用这种发电机的想法是这样的:

With the idea to consume this generator like so:

const resAfter = (val, delay) => new Promise(res => setTimeout(() => res(val), delay));
const rejAfter = (val, delay) => new Promise((_, rej) => setTimeout(() => rej(val), delay));

const promises = [
    resAfter("Third", 3000),
    resAfter("First", 1000),
    rejAfter("Second", 2000), // NOTE: this one rejects!
];

(async () => {

    let ordered = orderProms(promises);

    let done = false;
    for (let next_promise = ordered.next(); !done; next_promise = ordered.next()) {
        const next = await next_promise
            .catch(err => ({done: false, value: `Caught error: ${err}`}));

        done = next.done;
        if (!done) console.log(next.value);
    }
})()

但是,我注意到这将达到第二个承诺,然后生成器将停止.这似乎是因为被拒绝的第二"承诺.在 prom 被拒绝时,在生成器中调用 yield prom 会在生成器 中创建异常.

However, I've noticed that this will reach up to the second promise, then the generator will halt. It seems to be because of the rejected "second" promise. Calling yield prom in the generator will create an exception in the generator when the prom is rejected.

但这是我困惑的根源.我不想在这里创建异常,我只想将被拒绝的诺言作为迭代器结果的 value .我不希望将其打开.几乎就像这被视为 yield await prom; ,但是您可以看到没有 await 调用.

But this is the source of my confusion. I do not want to create an exception here, I just want to yield the rejected promise as the value of the iterator result. I don't want it to be unwrapped. It's almost like this is being treated as yield await prom;, but as you can see there is no await call.

这是怎么回事,我怎么能直接从生成器中产生被拒绝的诺言呢?

What is going on here and how can I simply yield a rejected promise as-is from this generator.

以下是可运行代码段中的上述代码:

Here's the above code in a runnable snippet:

async function* orderProms(prom_arr) {

    // Make a copy so the splices don't mess it up.
    const proms = [...prom_arr];

    while (proms.length) {
        // Tag each promise with it's index, so that we can remove it for the next loop.
        const {prom, index} = await Promise.race(proms.map((prom, index) => prom.then(
            () => ({prom, index}),
            () => ({prom, index})
        )));

        proms.splice(index, 1);
        yield prom;
    }
}

const resAfter = (val, delay) => new Promise(res => setTimeout(() => res(val), delay));
const rejAfter = (val, delay) => new Promise((_, rej) => setTimeout(() => rej(val), delay));

const promises = [
    resAfter("Third", 3000),
    resAfter("First", 1000),
    rejAfter("Second", 2000), // NOTE: this one rejects!
];

(async () => {

    let ordered = orderProms(promises);

    let done = false;
    for (let next_promise = ordered.next(); !done; next_promise = ordered.next()) {
        const next = await next_promise
            .catch(err => ({done: false, value: `Caught error: ${err}`}));

        done = next.done;
        if (!done) console.log(next.value);
    }
})()

推荐答案

这几乎就像被视为 yield await prom .这是怎么回事?

正是是异步生成器的行为.

Exactly that is how async generators behave.

我怎样才能简单地从此生成器中产生被拒绝的诺言.

how can I simply yield a rejected promise as-is from this generator.

您不能.请注意,

try {
    for await (const value of orderProms(promises)) {
        console.log(value);
    }
} catch(err) {
    console.error('Caught error: ', err);
}

语法中不方便进行单个错误处理.发生异常时,循环停止,生成器完成.点.

There is no facilitation for individual error handling in the syntax. When there's an exception, the loop stops, the generator is done. Point.

那你该怎么办?我看到三个选择:

So what can you do? I see three choices:

  • 只需保持原样,并尽早将失败视为一项功能(类似于 Promise.all )
  • 处理错误(在 orderProms 中或在将承诺传递到其中之前)并产生承诺状态和值的元组

  • just keep it as is and treat failing early as a feature (similar to Promise.all)
  • handle errors (either in orderProms or before passing promises into it) and yield tuples of promise status and value

for await (const value of orderProms(promises.map(prom =>
    prom.catch(err => `Caught error: ${err}`)
))) {
    console.log(value);
}

  • 使用普通的(非 async )生成器,您可以从中手动生成一个承诺,然后才能以期望的方式使用它
  • use a normal (non-async) generator from which you yield one promise after the other manually, to be able to use it in the way you want
  • 这篇关于异步生成器:产生被拒绝的承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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