1

I am wondering how to accomplish sharing values between "chain links" in Q promises without totally botching the pretty idiom of promises.

I am using Q to do some logic on mongo databases. My GET endpoint logic looks great:

return Q.ninvoke(this.db, 'collection', 'namespace')
  .then(function(namespaceCollection){
    return Q.ninvoke(namespaceCollection,'findOne',{"name":name})
  }).then(function(queryResults){
    if(!queryResults){
      throw new providerErrors.NotFound();
      return
    }
    return queryResults;
    },function(err){
      throw new providerErrors.BadRequest();
    });;

Applying the same pattern to my insert endpoint however, I run into a problem. I have to use the collection returned from the first promise, the one that gets the collection off the db object, in order to save the value back down:

return Q.ninvoke(this.db,'collection','namespace')
  .then(function(namespaceCollection){
     return Q.ninvoke(namespaceCollection,findOne,{"name":namespace.name}); 
  })
  .then(function(foundNamespace){
    if(namespace){
      throw new providerErrors.Conflict();
      return
    }
    //This is a new namespace object, give it a datetime and then
    //let's save it!
    namespace.createDate = new Date();
  })
  .then(function(namespaceToSave){
    //uhoh!  no collection in scope down here, just the value to persist!
  })

I'm wondering what's the best, most idiomatic way to solve this problem. I explored Q.all as a possible solution, but this obviously would not ensure the sequence of events.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
DeaconDesperado
  • 9,977
  • 9
  • 47
  • 77
  • exact duplicate of [How do I access previous promise results in a .then() chain?](http://stackoverflow.com/questions/28250680/how-do-i-access-previous-promise-results-in-a-then-chain) – Bergi Jan 31 '15 at 10:54

2 Answers2

1

Once you clean up the variable naming, you could just declare something in scope before the first Q.ninvoke. In the first callback, assign it to the CB value, then consume it in the third namespace.

var namespaceCollection = null;
return Q.ninvoke(this.db,'collection','namespace')
  .then(function(namespaceCol){
     namespaceCollection = namespaceCol;
     return Q.ninvoke(namespaceCollection,findOne,{"name": namespace.name}); 
  })
  .then(function(foundNamespace){
    if(!foundNamespace){
      throw new providerErrors.Conflict();
      return
    }
    //This is a new namespace object, give it a datetime and then
    //let's save it!
    namespace.createDate = new Date();
  })
  .then(function(namespaceToSave){
    // namespaceCollection is now available!
  })
David Souther
  • 8,125
  • 2
  • 36
  • 53
1

Works best to capture the value you need for subsequent steps in a closure. Promises can nest in handlers. Sequentiality is preserved by then, even in and out of the nested chains, by returning a promise from a handler.

return Q.ninvoke(this.db,'collection','namespace')
  .then(function(namespaceCollection){
    return Q.ninvoke(namespaceCollection,'findOne',{"name":namespace.name}); 
    .then(function(foundNamespace){
      return // presumably returning a promise for the namespace
             // to save here, otherwise, `then` chaining is unnecessary
    })
    .then(function(namespaceToSave){
      // namespaceCollection is in scope
    })
  })
Kris Kowal
  • 3,866
  • 2
  • 24
  • 24