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
For the paranoid: https://github.com/sindresorhus/loud-rejection
.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