0
function foo(options) {
  var deferred = q.defer();
  nonPromisifiedApi(options, deferred.resolve, deferred.reject);
  return deferred.promise;
}

function bar() {}

function bam() {}

foo({})
  .then(bar)
  .then(bam);

Will this code work as expected with both bar and bam being invoked in sequence, after the nonPromisifiedApi completes its asynchronous work?

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • 1
    Have you tested it ? looks like, `bar` will execute — then `bam` will execute but there is no promise between them .. So `bar` is not guaranteed to be complete when `bam` is ran! – Pogrindis Sep 11 '15 at 10:02
  • Your comment "have you tested it" can be applied to 50% of the comments on this site. I have just tested it and will add my findings to an answer. The remainder of your comment is plain wrong. – Ben Aston Sep 11 '15 at 10:15
  • Your `deferred.resolve` and `deferred.reject` are passed as functions not bound to actual deferred object. Also bar and bam will be executed one by one without any delay between – Andrey Sep 11 '15 at 10:16
  • Thank you for highlighting the binding problem. Given that it "works", however, I am suspicious whether q has pre-bound the functions for convenience. – Ben Aston Sep 11 '15 at 10:18
  • 1
    Also, be warn that the use of defer is non-standard and is now considered bad practice. You may consider the possibility to use the `Q.Promise` api. Even better, you can use an ES6 polyfill rather than `Q` (e.g. https://github.com/jakearchibald/es6-promise). Here is a nice article about promises: http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html. Reading it will probably answer most of the problem you may encounter. – Quentin Roy Sep 11 '15 at 10:24
  • @QuentinRoy so the deferred concept has been superseded/made obsolete? – Ben Aston Sep 11 '15 at 10:27
  • Yes. Promises are now part of the new Javascript version (ES6). Most modern browsers already support them natively. The correct way is just `new Promise(function(resolve, reject){ /* your stuff */});`. – Quentin Roy Sep 11 '15 at 10:41

2 Answers2

3

Here is a snippet showing you that it works well (using the syntax I was advising you).

function log(msg){ document.body.innerHTML += "<p>" + msg + "</p>"; }

function nonPromisifiedApi(options, fail, callback){
  log("nonPromisifiedApi");
  setTimeout(function(){
    callback("nonProm's async result");
  }, options.time);
}

function async(options){
  return Q.Promise(function(resolve, reject){
    nonPromisifiedApi(options, reject, function(val){
      log("async (val: " + val + ")");
      resolve("async's result");
    });
  });
}

function sync1(val){
  log("sync1 (val: " + val + ")");
  // filters the returned value
  return "sync1's result";
}

function sync2(val){
  log("sync2 (val: " + val + ")");
  // no return => undefined
}

async({time: 1000})
  .then(sync1)
  .then(sync2)
  .then(function(val){
     log("end (val: " + val + ")")
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/q.js/1.4.1/q.min.js"></script>

Once again, you won't lose your time when reading this article about promises.

And I think using an ES6 Promise polyfill rather that Q is likely to be a better option.

Quentin Roy
  • 7,677
  • 2
  • 32
  • 50
  • The deferred concept still has a use case in those rare occasions where the API of a non-promisified async function does not match the `resolve, reject` convention? Does the ES6 promise standard expose the concept of deferreds? – Ben Aston Sep 11 '15 at 10:47
  • Someone more expert than I am will probably tell you that he has never encounter a case where a deferred was required. The idea is that you do your stuff in the "body" of the promise. I have updated my snippet so it reflects a bit better your use case. – Quentin Roy Sep 11 '15 at 11:39
  • 2
    Oh, and no, there is no such things as deferred in the standard API. – Quentin Roy Sep 11 '15 at 13:37
0

Yes it will work as expected. q deals with non-promisified, synchronous functions in sequence (as might be expected), by silently wrapping them in a monadic API.

Ben Aston
  • 53,718
  • 65
  • 205
  • 331