简体   繁体   中英

Nodejs Promise.All with promise chain?

I'm not sure how to ask this question, but I have a set of promises that all need to be resolved as they are data api requests, but one of the three depends on the other and I'm not sure how to resolve.

The code in question looks like this:

    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);
    });

I have tried this code a few different ways based on the last 4 hours of googling, but haven't quite figured out what I'm doing wrong here.

You can do this with raw Promises, but it's kinda ugly. Much neater with 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);
}

NodeJS in non-blocking. All lines are executed synchronously, and dependent is surely undefined in Promise.all call because it was set to undefined in line let dependent;

.then callback is executed asynchronously, eg after all synchronous code.

If you want to use dependent which is resolved in then then you have to chain then calls.

I would refactor with async/await. To achieve the parallelization you are looking for we create two promises for (userInfo and dependent) and then use promise.All to await their resolution. promise.All returns an array of the result of all the promises.

Make sure to use a 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;
    });
}

I've tried to rejig your logic into promises -- one of the tools you can use for a chain of dependent promises is to declare your variables before the promise, and then set them in the .then -- that way the variable is available for all closures in the code block:

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
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM