
Question:
New to NodeJS. Going through the promise tutorial ('promise-it-wont-hurt') I have the following script:
var Q = require('q');
var deferred = Q.defer();
deffered.resolve('SECOND');
deffered.promise.then(console.log);
console.log('FIRST');
The output:
FIRST
SECOND
I don't get it, I would have thought that since resolved is fired first I should see second first.
They explain that this happens because of 'Promise fires on the same turn of the event loop'. I don't understand what that means...
Answer1:Basically, the point is that the promise's then
handler will <em>not</em> run before the current flow of code has finished executing and control is returned to the execution environment (in this case Node).
This is an important characteristic of Promises/A+ compliant promises because it ensures predictability. Regardless of whether the promise resolves immediately:
function getAPromise() {
var Q = require('q');
var deferred = Q.defer();
deferred.resolve('SECOND');
return deferred.promise;
}
getAPromise().then(console.log);
console.log('FIRST');
or whether it resolves after 10 seconds:
function getAPromise() {
var Q = require('q');
var deferred = Q.defer();
setTimeout(function () {
deferred.resolve('SECOND');
}, 10000);
return deferred.promise;
}
getAPromise().then(console.log);
console.log('FIRST');
you can be assured that FIRST
will always be logged first.
This is discussed at length in chapters 2 and 3 of <a href="https://github.com/getify/You-Dont-Know-JS/tree/master/async%20%26%20performance" rel="nofollow"><em>You don't know JS - async & performance</em></a>. Asynchronous operations that <em>sometimes</em> run asynchronously and <em>sometimes</em> run synchronously are called Zalgos, and they are not considered to be a good thing.
It's important to note that the widely used promises in jQuery <em>do not</em> obey this behavior and have a <a href="https://blog.domenic.me/youre-missing-the-point-of-promises/" rel="nofollow">number of other problems</a> as well. If you find yourself with a jQuery promise, wrap it in a proper promise and proceed:
Q($.ajax(...)).then(breatheWithEase);
Answer2:<blockquote>
They explain that this happens because of '<em>Promise fires on the same turn of the event loop</em>'. I don't understand what that means...
</blockquote>Me neither, imho this part doesn't make much sense. It probably should mean that when you call resolve
or reject
, the promise is settled immediately, and from then on will not change its state. This has nothing to do with the callbacks yet.
What is more important to understand is the next sentence in that paragraph:
<blockquote><em>You can expect that the functions passed to the "then" method of a promise will be called on the NEXT turn of the event loop.</em>
</blockquote>It's like a simple rule of thumb: then
callbacks are <em>always</em> called asynchronously. Always, in every proper promise implementation; this is mandated by the <a href="https://promisesaplus.com/#point-34" rel="nofollow">Promises/A+ specification</a>.
Why is this? For consistency. Unlike in your example snippet, you don't know how or when a promise is resolved - you just get handed it back from some method you called. And it might have already been resolved, or it might be still pending. Now you call the promise's then
method, and you can know: it will be asynchronous. You don't need to deal with cases that <a href="http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony" rel="nofollow">might be synchronous or not</a> and change the meaning of your code, it simply is always asynchronous.