Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplifying promises in Javascript

Are the following code snippets equivalent?

Version 1

function doSomething() {
  var defer = $q.defer();

  foo().then(function() {
    bar().then(function() {
      defer.resolve();
    });
  });

  return defer.promise;
}

Version 2

function doSomething() {
  return foo().then(bar);
}
like image 612
Misha Moroshko Avatar asked Jul 29 '14 11:07

Misha Moroshko


People also ask

What are the 3 states of a JavaScript promise?

A Promise is in one of these states: pending: initial state, neither fulfilled nor rejected. fulfilled: meaning that the operation was completed successfully. rejected: meaning that the operation failed.

What are promises in JavaScript?

A Promise is a JavaScript object that links producing code and consuming code.

How do you resolve a promise?

Promise resolve() method: Any of the three things can happened: If the value is a promise then promise is returned. If the value has a “then” attached to the promise, then the returned promise will follow that “then” to till the final state. The promise fulfilled with its value will be returned.

Why promises are used in JavaScript?

Promises are used to handle asynchronous operations in JavaScript. They are easy to manage when dealing with multiple asynchronous operations where callbacks can create callback hell leading to unmanageable code.


1 Answers

There are many differences between these two approaches.

The major difference between the two snippets is that in version 2 your are implicitly passing the resolved value from foo directly to bar. In addition to that doSomething will resolve whatever bar will resolve to, whereas in version 1 the result is discarded.

Some additional important points made by Benjamin Gruenbaum:

(a) if bar is a reference error 1 rejects the inner promise and 2 throws.
(b) 1 requires a reference to $q where 2 is implementation agnostic.
(c) version 1 is not exception safe and a rejection will be swallowed where version 2 will let you .catch a rejection. ; There are several smaller differences as well. See stackoverflow.com/questions/22539815

You could also write it like this.
This way you don't get the implicit pass trough of the resolved value from foo to bar ( it's explicit now ), which can be confusing or easily overlooked. It can also be useful if you want to do something with the resolved values of foo or bar before returning them.

function doSomething() {
  return foo().then(function(res){
     // maybe  do something with the result of foo
     return bar(res);
  }).then(function(res){
     // maybe do something with the result of bar
     return res;
  });
}

Manually creating a deferred object should be kept to a minimum and is generally an anti pattern.

https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns#the-deferred-anti-pattern

The key principle being demonstrated here is that a promise will adopt the state of the returned promise ( or thenable ) inside it's resolve method.

like image 116
Willem D'Haeseleer Avatar answered Oct 05 '22 23:10

Willem D'Haeseleer