简体   繁体   中英

Accommodating a Q.all in a promise chain

I swear by Q for its simplicity, so I might not have done much research checking out other 'then' implementations. But I've used Q a good deal!

I have a chain of 'then' promises, and I want to resolve a 'batch' of promises in the middle of it and proceed with other operations in sequence; so it's obvious I should use Q.all. But I'm stuck here. Either Q's doing it wrong, or I am.

Here are two hypothetical async operations

var f=function(delay){
  return Q.delay(delay).then(function(){
    console.log("returning delayed",delay)
    return delay
  })
}

f2=function(delay){
  var defer=Q.defer()
  setTimeout(function(){
    console.log("returning timedout",delay)
    return delay
  },delay)
  return defer.promise
}

And this is the promise chain

  Q('begin')
    .then(console.log)
    .then(Q.all([100,200,300,400].map(f)))
    .then(function(){
      console.log("Finally",arguments)
    }).done()

And this is the output I wish

begin
returning delayed 100
returning delayed 200
returning delayed 300
returning delayed 400
Finally { '0': undefined }

But this is the output I get

begin
Finally { '0': undefined }
returning delayed 100
returning delayed 200
returning delayed 300
returning delayed 400

I get the same sequence with f2

Now, if I run this

Q.all([100,200,300,400].map(f)).then(function(){
  console.log("Finally",arguments)
}).done()

I do get

returning delayed 100
returning delayed 200
returning delayed 300
returning delayed 400
Finally { '0': [ 100, 200, 300, 400 ] }

but using f2 instead of f gives me

returning timedout 100
returning timedout 200
returning timedout 300
returning timedout 400

It doesn't execute the finally block.

I get the same outputs with Q.[all/allResolved/allSettled]

So, my queries are,

  1. How do I achieve the intended output by using Q.all specifically. I do have a workaround though, but it doesn't look nice.
  2. How are f and f2 different since the results by running Q.all().then() with them aren't the same.

Q.all takes an array of promises, but then returns a promise (that is the only resolved when every promise in the array is resolved.

So, I think you need to return the result of Q.all in order to not immediately call the next then :

Q('begin')
    .then(console.log)
    .then(function() {
        return Q.all([100,200,300,400].map(f));
    })
    .then(function(){
      console.log("Finally",arguments)
    }).done()

Answering the second question, your usage of f2 is incorrect.

When you create a promise using a deferred you must resolve it in order for it to become fulfilled. You can read more about it in How to convert a callback API to promises .

In your case you're creating an empty deferred and returning its promise but you never actually call .resolve on the deferred. Doing it "more correctly" would be something like:

f2=function(delay){
  var defer=Q.defer()
  setTimeout(function(){
    console.log("returning timedout",delay)
    defer.resolve(delay); // note the resolve here vs the return
  },delay)
  return defer.promise
}

Using Q.delay works better since it's already promisified. As for other then implementations Q is hardly bleeding edge right now to say the least :)

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