29608

What does “Promise fires on the same turn of the event loop” mean?

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.

Recommend

  • Android onKey w/ virtual keyboard
  • How to skip require in ruby?
  • Simple linked list-C
  • Redshift Querying: error xx000 disk full redshift
  • Saving image to sd with current date and time in name doesn't work
  • DIV instruction jumping to random location?
  • Bash if statement with multiple conditions
  • How to remove a SwiftyJSON element?
  • CakePHP ACL tutorial initDB function warnings
  • Diff between two dataframes in pandas
  • Moving Android View and preventing onDraw to be called over and over again
  • xtable package: Skipping some rows in the output
  • Detect when Facebook like button is clicked
  • Caching attributes in superclass
  • AJAX Html Editor Extender upload image appearing blank
  • Swift: Switch statement fallthrough behavior
  • Yii2: Config params vs. const/define
  • Is it possible to access block's scope in method?
  • SignalR .NET Client Invoke throws an exception
  • Nant, Vault & Windows Integrated Authentication
  • How to make a tree having multiple type of nodes and each node can have multiple child nodes in java
  • Bug in WPF DataGrid
  • How to make Safari send if-modified-since header?
  • jQuery tmpl and DataLink beta
  • How can I estimate amount of memory left with calling System.gc()?
  • 0x202A in filename: Why?
  • How to pass list parameters for each object using Spring MVC?
  • SVN: Merging two branches together
  • Hibernate gives error error as “Access to DialectResolutionInfo cannot be null when 'hibernate.
  • PHP: When would you need the self:: keyword?
  • WPF Applying a trigger on binding failure
  • Acquiring multiple attributes from .xml file in c#
  • How to CLICK on IE download dialog box i.e.(Open, Save, Save As…)
  • Exception on Android 4.0 `android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode)`
  • Setting background image for body element in xhtml (for different monitors and resolutions)
  • Can Visual Studio XAML designer handle font family names with spaces as a resource?
  • JaxB to read class hierarchy
  • reshape alternating columns in less time and using less memory
  • How can i traverse a binary tree from right to left in java?
  • How can I use threading to 'tick' a timer to be accessed by other threads?