Bluebird's Promise.all() method when one promi

2020-07-12 05:31发布

问题:

I'm writing some code that currently looks like this because I have dependencies in my code. I was wondering if there was a cleaner way to do this with Promise.all()? Here is my pseudo code:

        return someService.getUsername()
            .then(function(username) {
                user = username;
            })
            .then(function() {
                return someService.getUserProps(user);
            })
            .then(function(userProps) {
                userProperties = userProps;
                return someService.getUserFriends(user);
            })
            .then(function(userFriends) {
                friends = userFriends;
            })
            .catch(error)
            .finally(function(){
                // do stuff with results
            });

The important thing is that I need user before I can make the second two calls for getUserProps() and getUserFriends(). I thought I could use Promise.all() for this like so:

var user = someService.getUsername()
    .then(function(username) {
        user = username;
    })
var getUserProps = someService.getUserProps(user);
var getUserProps = someService.getUserFriends(user);

return Promise.all(user, getUserProps, getUserFriends, function(user, props, friends) {
    // do stuff with results
})

But I cannot get this to work. Is this the correct case to use .all?

回答1:

Promise.all() is designed for parallel operation where you launch a bunch of async operations to run at the same time and then it tells you when they are all done.

It does not sequence one versus the completion of another in any way. So, you can't use it to wait for the user to be ready and then have the other operations use that user. It just isn't designed to do that.

You could get the user first and then when that is complete, you could use Promise.all() with your other two operations which I think can be run at the same time and don't depend upon each other.

var user;
someService.getUsername().then(function(username) {
    user = username;
    return Promise.all(getUserProps(user), getUserFriends(user));
}).then(function() {
    // do stuff with results array
}).catch(function() {
    // handle errors
});


回答2:

You can use .all but you're going to have to make sure they run sequentially your code, you can do this by .thening them like you've done. If you do that you should use .join which is a shorthand for .all([...]).spread(....

var user = someService.getUsername();
var props = user.then(getUserProps)
var friends = user.then(getUserFriends)
Promise.join(user, props, friends, function(user, props, friends) {

    // everything is available here, everything is synchronized
});

If what you were trying to solve is the closure/nesting issue - then this is the way to do so.



回答3:

Promise.all() is a way to execute a list of promises in parallel but if we want to execute a list of promises in a series where one is dependent on the other, we've to solve it a bit differently

// Promise returning functions to execute
function doFirstThing(){ return Promise.resolve(1); }  
function doSecondThing(res){ return Promise.resolve(res + 1); }  
function doThirdThing(res){ return Promise.resolve(res + 2); }  
function lastThing(res){ console.log("result:", res); }

var fnlist = [ doFirstThing, doSecondThing, doThirdThing, lastThing];

// Execute a list of Promise return functions in series
function pseries(list) {  
  var p = Promise.resolve();
  return list.reduce(function(pacc, fn) {
    return pacc = pacc.then(fn);
  }, p);
}

pseries(fnlist);  
// result: 4