Les promesses
"Une promesse est une abstraction logicielle qui rend plus agréable le fait de travailler avec du code asynchrone"
Domenic Denicola, co-creator of Q
En javascript
Specification (+ compliance test) : promisesaplus.com
Implémentations
Autres librairies compatibles Promise/A+ :
"Callback hell" 😱
Pyramid of Doom
C'est déjà plus lisible ! 🙂
var floppy = require('floppy');
floppy.load('disk1')
.then((data1) => floppy.prompt('Please insert disk 2'))
.then(() => floppy.load('disk2'))
.then((data2) => floppy.prompt('Please insert disk 3'))
.then(() => floppy.load('disk3'))
.then((data3) => floppy.prompt('Please insert disk 4'))
.then(() => floppy.load('disk4'))
.then((data4) => floppy.prompt('Please insert disk 5'))
.then(() => floppy.load('disk5'))
.then((data4) => floppy.prompt('OK!'));
Si floppy.load() et floppy.prompt() retournent une promesse
floppy.load("disk1", function (err, results) {
// the rest of your code goes here.
});
floppy.load("disk1").then(function() {
// the rest of your code goes here.
});
devient (si load() retourne un "then-able") :
Sans promesse :
Coder un "thenable" simple !
Resolve & Reject
floppy.load = new Promise(function(resolve, reject) {
// faire un truc, peut-être asynchrone, puis…
if (/* tout a bien marché */) {
resolve("Ces trucs ont marché !"); // <== FULFILLED
}
else {
reject(Error("Ça a foiré")); // <== REJECTED
}
});
Déclaration :
Utilisation :
getJSON('story.json').then(function getChapter1(story) {
// [...] display chapter 1 & returns a promise
}).then(function getChapter2() {
// [...] display chapter 2 & returns a promise
}).then(function getChapter3() {
// [...] display chapter 3
})
/**
* Generates a promise adding 10 to a value after 1 sec
*/
function getPromise(value) {
return new Promise(function(resolve, reject) {
setTimeout(function() { resolve(value + 10); }, 1000);
});
}
/**
* Promises sequence
*/
getPromise(0)
.then(result => getPromise(result))
.then(result => getPromise(result))
.then(result => {
console.log(result);
});
Que vaut "result" à la fin ?
cf. http://bevacqua.github.io/promisees
catch
new Promise(function(resolve, reject) {
setTimeout(function() { reject('ERR!'); }, 3000);
})
.then(function(e) { console.log('done', e); })
.catch(function(e) { console.log('catch: ', e); });
// From the console:
// 'catch: ERR!'
cf. http://bevacqua.github.io/promisees
var log = "";
function doWork() {
log += "W";
return Promise.resolve();
}
function doError() {
log += "E";
throw new Error("oops!");
}
function errorHandler(error) {
log += "H";
}
doWork()
.then(doWork)
.then(doError)
.then(doWork)
.then(doWork, errorHandler)
.then(verify);
function verify() {
console.log(log);
done();
}
1) Lors d'une exception, les "then" suivants ne sont pas exécutés jusqu'à tomber sur un "catch".
2) Après un "catch", on reprend la chaine classique (on repasse dans le "then").
Que vaut "log" ?
var request1 = fetch('/users.json');
var request2 = fetch('/articles.json');
Promise.all([request1, request2]).then(function(results) {
// Both promises done!
});
Promise.all
getJSON('story.json').then(function(story) {
return Promise.all([getChapter1(), getChapter2(), getChapter3()])
}).then(function(results) {
// Display chapter 1, 2 & 3
});
const p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, "one");
});
const p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, "two");
});
const p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, "three");
});
Promise.all([p1, p2, p3]).then(value => {
console.log(value);
}, reason => {
console.log(reason)
});
const p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "one");
});
const p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// Both resolve, but p2 is faster
});
On récupère ainsi la première qui est "fulfilled"
https://pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html
getArticleId()
.then(id => getArticleContent(id))
.then(content => console.log(content));
getArticleId() et getArticleContent() retournent une Promise
Sachant que :
Avec une séquence de "then" :
// Await ne marchera que dans une fonction marquée async
async function getMyArticle() {
const id = await getArticleId();
const content = await getArticleContent(id);
console.log(content);
return content;
}
Avec async/await :
async function getMyArticle() {
const id = await getArticleId();
const content = await getArticleContent(id);
return content;
}
On peut l'apeller avec un autre async
async function read() {
var content = await getMyArticle();
console.log(content);
}
Ou l'utiliser comme une promesse
getMyArticle().then(content => console.log(content));
async function concurrent () {
const [r1, r2, r3] = await Promise.all([p1, p2, p3]);
}
async function getMyArticle() {
const id = await getArticleId();
if (id === null) {
throw 'err';
} else {
return content;
}
}
Déjà vu ?
async function read() {
try {
var content = await getMyArticle();
} catch (err) {
console.error(err);
}
}
exercice, vite fait !
Avec Babel REPL, écrire une suite de promesses pour :