【问题标题】:Dynamically fill a Promise.all()动态填充一个 Promise.all()
【发布时间】:2018-11-20 12:19:33
【问题描述】:

我试图弄清楚为什么这段代码不起作用。我正在循环一个依赖树(deepObject),并且对于每个我想运行一个返回承诺的函数。然后,我希望在解决所有承诺之后发生下一组功能,但是 promise.all 中的控制台日志没有执行。 ES6 也很酷,如果你有更好的方法,但是我也很想知道为什么这段代码不起作用。

更新为添加.catch(这没有效果)

for (let i = 0; i < keys.length; i++) {
    promisesArray.push(promiseFunction(deepObject[keys[i]]));
}
Promise.all(promisesArray).then(resolved => {
    console.log('dep promises resolved');
    console.log(`resolved: ${JSON.stringify(resolved)}`);
}).catch(err => console.error(new Error(err));

// promiseFunction is recursive
promiseFunction(obj) {
    return new Promise((resolve, reject) => {

        const keys = Object.keys(deepObj);
        for (let j = 0; j < keys.length; j++) {
            if (Object.keys(deepObj[keys[j]]).length) {
                // adding return statement to following line breaks it
                // that was already recommended, see threads
                promiseFunction(deepObj[keys[j]]);
            } else {
                const dep = new Package(keys[j]);
                console.log(`skan dep: ${keys[j]}`);
                dep.fetch().then(() => {
                    return anotherFunction();
                }).then(() => {
                    return Promise.all([
                        promise1(),
                        promise2(),
                        promise3(),
                    ]).then(resolved => {
                        if (resolved[0].propertyINeed) {
                            resolve(true);
                        }
                        resolve(false);
                    });
                }).catch(err => {
                    console.error(new Error(err));
                    process.exit(1);
                });
            }
        }
    });

我知道这个对话 - has been discussed - on here before

在上面的第二个链接中,接受的答案建议:

如果您异步填充数组,您应该获得该数组的承诺,并使用 .then(Promise.all.bind(Promise))。如果您不知道何时停止添加 Promise,那么无论如何这都是不可能的,因为它们可能永远都不会被解决。

但是我没有使用异步来填充数组。我需要这个吗?我在这里错过了什么?

更新

由于我现在在 .then().catch() 中都有错误记录,因此似乎出现了与其中发生的事情无关的问题。

promiseFunction(deepObj[keys[j]]); 之前添加return 语句会破坏递归。我从 173 个对象迭代到 68 个对象。添加 catch 没有记录额外的结果。上面的代码已更新以共享更多递归 fn。当我运行它时,它似乎执行了所有的承诺,但我无法知道这一点。我最关心的是知道 1. promise.all 的 promise 数组包含它应该包含的所有对象,以及 2. 抓住递归对象中所有对象的所有这些 promise 都已解决的时刻。

此外,为了记录,这些返回承诺的函数中的每一个都必须是异步的。我已经多次回顾所有这些,试图简化和删除任何不必要的承诺。任务很复杂。有一系列步骤必须执行,它们是异步的,并且它们是链式的,因为它们必须按特定顺序解决。

【问题讨论】:

  • 尝试控制台记录拒绝功能,看看是否有问题
  • "promiseFunction 为简洁省略" — 不要那样做。你不需要提供真实的东西,但你需要提供minimal reproducible example。我已经猜到哪些代码可能会出现在丢失的地方,但我无法重现该问题:jsbin.com/fesudezuja/1/edit?js,console
  • 试试Promise.all(promisesArray).then(...).catch(err =&gt; console.error('Failed', err))
  • promiseFunction 中,if 语句的第一个块应该return 第二个promiseFunction 的结果 - 否则它不会解决任何问题!

标签: javascript asynchronous promise


【解决方案1】:
if (Object.keys(obj[keys[j]]).length) {
    promiseFunction(obj[keys[j]]);
} else {
    // and some more async hell that all resolves correctly

如果Object.keys(obj[keys[j]]).lengthtrue,那么你永远不会调用resolvereject,所以promise 永远不会解决。

(请注意,递归调用 promiseFunction 会创建一个 new 承诺,该承诺永远不会放入 Promise.all)。

由于您的某些承诺没有解决,Promise.all 也不会。


你可能需要更多类似的东西:

var promises = [];
processObject(obj);
Promise.all(promises).then(etc etc);

function processObject(object) {
    for ( loop; over; object ) {
        if (condition) {
             processObject(object[something]);
        } else {
             promises.push(new Promise( (res, rej) => {
                 // so something async
             });
        }
    }
}

【讨论】:

  • 我已尝试在最新更新中解决所有 cmets。
  • 递归确实包含解析/拒绝语句
  • 不是正确的。我请您回到我所说的部分:(请注意,递归调用 promiseFunction 会创建一个从未放入 Promise.all 的新 Promise)。
  • 你为什么用new Promise开头?
  • @Kraken — “promiseFunction 返回一个 Promise” — 这会创建 Promise A。如果您点击 if 语句,那么它会递归调用自身。这将创建 Promise B。如果达到 else,则 Promise B 已解决。承诺 A 未解决。
【解决方案2】:

让我们看看你的promiseFunction...

for (let j = 0; j < keys.length; j++) {
    if (Object.keys(obj[keys[j]]).length) {
        //if you get in here, promiseFunction returns undefined, and it never gets resolved
        promiseFunction(obj[keys[j]]);
    } else {
        const dep = new Package(keys[j]);
        console.log(`skan dep: ${keys[j]}`);
        // and some more async hell that all resolves correctly
        //but even if it resolves correctly, you still have the if...
    }
}

要做到这一点,只需在 if 语句中返回您的 promiseFunction 结果:

for (let j = 0; j < keys.length; j++) {
    if (Object.keys(obj[keys[j]]).length) {
        //if you get in here, you're saying this promise will depend on how this second promiseFunction will resolve
        return promiseFunction(obj[keys[j]]);
    } else {
        //omitted for brevity...
        resolve('your value');
    }
}

现在,当您进入 if 语句时,您基本上是根据第二个 promiseFunction 是否正确解决来告诉 Promise 解决 - 您将解决方案委托给另一个 Promise。

我从来没有听说过有人给它起这个名字,但你可以把它想象成 Promise 递归 :)

【讨论】:

  • 我已尝试在最新更新中解决所有 cmets。
  • 添加return语句似乎会破坏它
猜你喜欢
  • 1970-01-01
  • 2020-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-23
  • 2014-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多