Promises

You will learn something, I promise

Nordnet Academy

Agenda

  • Background and intro
  • Common mistakes, and how to avoid.
  • ProTips and some Aaaah's.
  • Q&A

Background

Async Programming === Callback hell

getData(a => {
    getMoreData(a, b =>{
        getMoreData(b, c => {
            getMoreData(c, d => {
                console.log(d);
            });
        });
    });
});

function getMoreData(input, callback) {
  setTimeout(callback, 10, input + 1);
}

function getData(callback){
  callback(1);
}

1 - callbackHell.js

 

console

$ node callbackHell.js
4

Promises

To the rescue!

console.log('1');
const promise = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 'Done');
});
 

2 - promise.js

console

$ node promise.js                                                         07:57:57
1
2
3
Done
$
console.log('2');
promise
  .then(result => console.log(result))
  .catch(error => console.error(error));
console.log('3');

Chain of Promises

new Promise((resolve, reject) => resolve(1))
  .then(getMoreData)
  .then(getMoreData)
  .then(getMoreData)
  .then(result => console.log(result))
  .catch(error => console.error(error));

function getMoreData(data){
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 10, data + 1);
  })
}

3 - chaining.js

 

console

$ node chaining.js
4
Promise.resolve(1)
  .then(getMoreData)
  .then(result => console.log(result))
  .catch(error => console.error(error));

Common mistakes

Side effects vs return

getUserByName('nolan').then(user => {
  getUserAccountById(user.id);
}).then( account => {
  // account is not valid here nor resolved
});

4 - sideEffects.js

 

4 - without side effects

getUserByName('nolan').then(user => {
  if (inMemoryCache[user.id]) {
    return inMemoryCache[user.id];    // returning a synchronous value!
  }
  return getUserAccountById(user.id); // returning a promise!
}).then(userAccount => {
  // I got a user account!
});

Pyramid of Doom

remotedb.allDocs()
  .then(result => {
    var docs = result.rows;
    docs.forEach(element => {
      localdb.put(element.doc).then(response => {
        alert("...");
      }).catch(err => {
        if (err.status == 409) {
          localdb.get(element.doc._id).then(resp => {
            localdb.remove(resp._id, resp._rev).then(resp => {
// et cetera...

5 - Pyramid of Doom

 

5 - Chained Promises

remotedb.allDocs(...)
  .then(resultOfAllDocs => {
    return localdb.put(...);
  }).then(resultOfPut => {
    return localdb.get(...);
  }).then(resultOfGet => {
    return localdb.put(...);
  }).catch(err => {
    console.log(err);
  });

No Catch

somePromise().then(() => {
  return anotherPromise();
}).then(() => {
  return yetAnotherPromise();
})

6 - noCatch.js

.catch(console.error.bind(console));
  • Will silently swallow all errors

.then().catch()

vs

then(funA, funC)

 

7 - .then(funcA, funcB)

 

7 - .then().catch()

new Promise().then(resolveHandler, errorHandler);

7 - .then(resolveHandler, errorHandler)

somePromise().then(() => {
  throw new Error('oh noes');
}, err => {
  // I didn't catch your error! :(
});
somePromise().then(() => {
  throw new Error('oh noes');
}).catch(err => {
  // I caught your error! :)
});

Promises fall through

Promise.resolve('foo')
  .then(Promise.resolve('bar'))
  .then(result => {
    console.log(result);
  });

8 - fallThrough.js

 

console

 

8 - nonFallThrough.js

 

console

$ node fallThrough.js
foo
$ node nonFallThrough.js
bar
Promise.resolve('foo')
  .then(() => {
    return Promise.resolve('bar');
  })
  .then(result => {
    console.log(result);
  });

ProTips

Promise.all()

db.allDocs().then(result => {
  return Promise.all(
    result.rows.map(row => db.remove(row.doc))
  );
}).then(arrayOfResults => {
  // All docs have really been removed() now!
});

9 - promiseAll.js

Promise.race()

const p1 = new Promise((resolve, reject) => { 
    setTimeout(resolve, 500, "one"); 
});
const p2 = new Promise((resolve, reject) => { 
    setTimeout(resolve, 100, "two"); 
});

Promise.race([p1, p2]).then(value => {
  console.log(value); // "two"
  // Both resolve, but p2 is faster
});

9 - promiseRace.js

Rejections

new Promise((resolve, reject) => {
  reject(new Error('Because: rejected!'));
})

10 - rejections.js

  .then(result => {
    throw new Error('Because: thrown')
  })
  .then(result => {
    return Promise.reject('Because: Reasons')
  })
  .catch(console.error.bind(console))

Multiple ways to reject a promise

  • reject callback
  • Throw
  • Promise.reject

Defer is an Anti-pattern!

function brokenAsyncGreet(name) {
  var deferred = $q.defer();

  setTimeout(function() {
    if (okToGreet(name)) {
      deferred.resolve('Hi ' + name);
    } else {
      deferred.reject('Not allowed');
    }
  }, 1000);

  return deferred.promise;
}

11 - deferredPromise.js

 

11 - properPromise

This is for all the Angular's.

function asyncGreet(name) {
  return $q(function(resolve, reject) {
    setTimeout(function() {
      if (okToGreet(name)) {
        resolve('Hello, ' + name);
      } else {
        reject('Not allowed');
      }
    }, 1000);
  });
}

Keep calm in case of:

Q & A

Promises

By nordnetacademy

Promises

  • 1,018