【问题标题】:Nodejs Promise.All with promise chain?Nodejs Promise.All 带有承诺链?
【发布时间】:2020-04-24 06:04:17
【问题描述】:

我不知道如何问这个问题,但我有一组需要解决的承诺,因为它们是数据 api 请求,但三个中的一个取决于另一个,我不确定如何解决。

有问题的代码如下所示:

    let dependent;

    let subscriptions = getSubscriptions() //data fetch
       .then((subscriptions) => {
            let fieldList = subscriptions.reduce((subscription) => {
               if(subscription.Threshold) {
                  return subscription.Threshold.Field;
               }
               return null;
           });
           dependent = getUpdatedInfo(request, body, fieldList); //Data fetch promise
           return subscriptions;
       });

    let userInfo = getUserInformation(); //Data fetch

    Promise.all([subscriptions, userInfo, dependent]).then(function(values) {
        console.log({ promiseAll: values }); //Dependent is always undefined
        processSubscriptions(result, body, userInfo, subscriptions, dependent);
    });

根据过去 4 小时的谷歌搜索,我已经尝试了几种不同的方法,但还没有完全弄清楚我在这里做错了什么。

【问题讨论】:

  • 如果其中一个依赖于其他,那么它不是原始 Promise.all 集合的一部分,因为它不可能。所以你会得到Promise.all([independent tasks]).then(results => promiseBasedOn(results)).then( data => now we're done )
  • @Mike'Pomax'Kamermans 哇。我是一个白痴。你介意把这个作为答案吗?
  • 老实说,不确定这是否构成一个真正的问题。问题主要是你忘了点东西。它也有很多反对意见,所以再次删除它可能更有效率?
  • 我想如果你不想要功劳,哈哈

标签: javascript node.js promise fetch


【解决方案1】:

NodeJS 处于非阻塞状态。所有行同步执行,dependentPromise.all 调用中肯定是未定义的,因为它在let dependent; 行中设置为undefined

.then 回调是异步执行的,例如所有同步代码之后。

如果您想使用在then 中解析的dependent,那么您必须链接then 调用。

【讨论】:

    【解决方案2】:

    你可以用原始的 Promise 做到这一点,但它有点难看。使用 async/await 会更整洁:

    async function whatever() {
      const subs = await getSubscriptions();
      const fieldList = subs.reduce((subscription) => {
        if(subscription.Threshold) {
          return subscription.Threshold.Field;
        }
          return null;
        });
      const dependent = await getUpdatedInfo(request, body, fieldList);
      const userInfo = await getUserInfo();
      return processSubscriptions(result, body, userInfo, subscriptions, dependent);
    }
    

    【讨论】:

    • 我不得不在这里使用 promise,因为 fetch api 是基于 promise 的
    • @CBauer async/await is 承诺。这只是.then 的语法糖。
    • @CBauer async/awaitPromise 的语法糖,因此这是正确的。
    • 这应该可以,但不能实现并行化,所以会更慢。
    • @FakeFootball 慢?是的。慢到重要吗?可能不是。在分析器告诉我需要之前,我不会为了速度而牺牲干净可读的代码。
    【解决方案3】:

    我会用 async/await 重构。为了实现您正在寻找的并行化,我们为(userInfo 和dependent)创建了两个promise,然后使用promise.All 等待它们的解决。 promise.All 返回所有 promise 的结果数组。

    确保使用try,catch

    async function processSubscriptionsHandler(request, body) {
        try {
            let userInfoPromise = getUserInformation(); // async function returning a promise
            let subscriptions = await getSubscriptions()
            let fieldList = getFieldList(subscriptions)
            let dependentPromise = getUpdatedInfo(request, body, fieldList) // async function returning a promise
    
            let [userInfo, dependent] = await Promise.all([userInfoPromise, dependentPromise]) // await both promises to resolve and map resulting array to variables
    
            processSubscriptions(result,
                body,
                userInfo,
                subscriptions,
                dependent);
        } catch (e) {
            console.error(e)
        }
    }
    
    function getFieldList(subscriptions) {
        subscriptions.reduce((subscription) => {
            if (subscription.Threshold) {
                return subscription.Threshold.Field;
            }
            return null;
        });
    }
    

    【讨论】:

      【解决方案4】:

      我尝试将您的逻辑重新设置为 Promise - 您可以用于一系列依赖 Promise 的工具之一是在 Promise 之前声明您的变量,然后将它们设置在 .then 中 - 这样该变量可用于代码块中的所有闭包:

      let subscriptions;
      let updatedInfo;
      let subscriptionsPromise = getSubscriptions() //data fetch
         .then((subscriptionsResults) => {
              let fieldList = subscriptionsResults.reduce((subscription) => {
                 if(subscription.Threshold) {
                    return subscription.Threshold.Field;
                 }
                 return null;
             });
             subscriptions = subscriptionsResults
             return getUpdatedInfo(request, body, fieldList); //Data fetch promise
         })
         .then(updatedInfoResult => {
             updatedInfo = updatedInfoResult;
         });
      
      let userInfoPromise = getUserInformation(); //Data fetch
      
      Promise.all([subscriptionsPromise, userInfoPromise]).then(function(values) {
          // at this point, subscriptions should have a value, 
          // and so should updatedInfo,
          // and values[1] should be the result from userInfoPromise
      });
      

      【讨论】:

        猜你喜欢
        • 2018-01-31
        • 2018-05-03
        • 2017-11-15
        • 2018-11-18
        • 2022-08-20
        • 2020-03-12
        • 2018-11-03
        • 1970-01-01
        • 2018-05-11
        相关资源
        最近更新 更多