steam learn: asynchronous javascript
TRANSCRIPT
6th of June, 2015
Asynchronous JavascriptCommon and useful patterns
by Steven Rémot
6th of June, 2015
Table of contents
1. Callbacks
2. Promises
3. Generators
6th of June, 2015
Table of contents
1. Callbacks
2. Promises
3. Generators
6th of June, 2015
Callbacks - Usage
function GameController() { var dirChangedCb = function () {};
this.onDirectionChanged = function (callback) { dirChangedCb = callback; };
document.addEventListener('keydown', function (event) { dirChangedCb(determineEventDirection(event)); });}
var gc = new GameController();gc.onDirectionChanged(function (direction) { hero.move(direction);});
6th of June, 2015
Callbacks - Avoiding conflicts
function GameController() { var dirChangedCb = function () {};
this.onDirectionChanged = function (callback) { dirChangedCb = callback; };
document.addEventListener('keydown', function (event) { dirChangedCb(determineEventDirection(event)); });}
var gc = new GameController();gc.onDirectionChanged(function (direction) { hero.move(direction);});
gc.onDirectionChanged(function (direction) { enemy.reactTo(direction);});
Only one callback is saved
6th of June, 2015
Callbacks - Avoiding conflicts
function GameController() { var dirChangedCbs = [];
this.onDirectionChanged = function (callback) { dirChangedCbs.push(callback); };
document.addEventListener('keydown', function (event) { for (var i = 0; i < dirChangedCbs.length; i++) { dirChangedCbs[i](determineEventDirection(event)); } });}
var gc = new GameController();gc.onDirectionChanged(function (direction) { hero.move(direction);});
gc.onDirectionChanged(function (direction) { enemy.reactTo(direction);});
6th of June, 2015
Callbacks - Nested operations
function loadHero(loadingFinishedCallback) { http.get('/characters/hero.json', function (heroData) { loadingFinishedCallback({ data: heroData }); });}
6th of June, 2015
Callbacks - Nested operations
function loadHero(loadingFinishedCallback) { http.get('/characters/hero.json', function (heroData) { http.get(heroData.modelUrl, function (model) {
loadingFinishedCallback({ data: heroData, model: model });
}); });}
6th of June, 2015
Callbacks - Nested operations
function loadHero(loadingFinishedCallback) { http.get('/characters/hero.json', function (heroData) { http.get(heroData.modelUrl, function (model) { http.get(model.materialUrl, function (material) {
loadingFinishedCallback({ data: heroData, model: model, material: material });
}); }); });}
6th of June, 2015
Callbacks - Nested operations
function loadHero(loadingFinishedCallback) { http.get('/characters/hero.json', function (heroData) { loadGraphics(heroData.modelUrl, function (graphics) {
loadingFinishedCallback({ data: heroData, model: graphics.model, material: graphics.material });
}); });}
6th of June, 2015
Callbacks - Limits
● Nested callbacks are not handy
● Even worse with error catching
● Waiting for multiple callbacks is hard
Callbacks are bad for async operations
6th of June, 2015
Table of contents
1. Callbacks
2. Promises
3. Generators
6th of June, 2015
Promises - Basics
function httpGet(url) { return new Promise(function (resolve) { http.get(url, function (data) { resolve(data); }); });}
6th of June, 2015
Promises - Basics
function httpGet(url) { return new Promise(function (resolve) { http.get(url, resolve); });}
6th of June, 2015
Promises - Basics
function httpGet(url) { return new Promise(function (resolve, reject) { http.get(url, resolve, reject); });}
6th of June, 2015
Promises - Chaining
function loadHero() { return httpGet('/characters/hero.json') .then(function (heroData) { return { data: heroData }; });}
loadHero().then(function (hero) { console.log(hero.data);});
6th of June, 2015
Promises - Chaining
function loadHero() { return httpGet('/characters/hero.json') .then(function (heroData) {
return httpGet(heroData.modelUrl).then(function (model) { return { data: heroData, model: model }; });
});}
loadHero().then(function (hero) { console.log(hero.data); console.log(hero.model);});
6th of June, 2015
Promises - Chaining
function loadHero() { var hero = {}; return httpGet('/characters/hero.json') .then(function (heroData) { hero.data = heroData; return httpGet(heroData.modelUrl); }) .then(function (model) { hero.model = model; return hero; });}
loadHero().then(function (hero) { console.log(hero.data); console.log(hero.model);});
6th of June, 2015
Promises - Chaining
function loadHero() { var hero = {}; return httpGet('/characters/hero.json') .then(function (heroData) { hero.data = heroData; return httpGet(heroData.modelUrl); }) .then(function (model) { hero.model = model; return httpGet(model.materialUrl); }) .then(function (material) { hero.material = material; return hero; });}
6th of June, 2015
Promises - Chaining
function loadHero() { var hero = {}; return httpGet('/characters/hero.json') .then(function (heroData) { hero.data = heroData; return httpGet(heroData.modelUrl); }) .then(function (model) { hero.model = model; return httpGet(model.materialUrl); }) .then(function (material) { hero.material = material; return hero; }) .catch(function (error) { console.log(error); return null; });
6th of June, 2015
Promises - Waiting all promises
function loadObjects() { return Promise.all([ loadHero(), loadEnemy(), loadDoor(), loadWall(), // ... ]);}
loadObjects().then(function (objects) { var hero = objects[0]; var enemy = objects[1]; // ...});
6th of June, 2015
Promises - How to get them
● In Ecmascript 6 standard library
● Available through polyfills:https://github.com/jakearchibald/es6-promise
● Alternative APIs:https://github.com/kriskowal/qhttps://github.com/petkaantonov/bluebird
6th of June, 2015
Promises
Nice, but…
● Verbose
● Still writing in an asynchronous way
We can do better!
6th of June, 2015
Table of contents
1. Callbacks
2. Promises
3. Generators
6th of June, 2015
Generator - Basics
function* counter() { for (var i = 0; i < 10; i++) { yield i; }}
var count = counter();console.log(count.next()); // 0console.log(count.next()); // 1// ...
6th of June, 2015
Generator - Basics
function* loadHero(){ var hero = {};
hero.data = yield httpGet('/characters/hero.json'); hero.model = yield httpGet(hero.data.modelUrl); hero.material = yield httpGet(hero.model.materialUrl);
return hero;}
spawn(loadHero).then(function (hero) { console.log(hero); // { data: <...>, model: <...>, ... }});
6th of June, 2015
Generator - Basics
function* loadHero(){ var hero = {};
try { hero.data = yield httpGet('/characters/hero.json'); hero.model = yield httpGet(hero.data.modelUrl); hero.material = yield httpGet(hero.model.materialUrl); } catch (error) { console.log(error); hero = null; }
return hero;}
spawn(loadHero).then(function (hero) { console.log(hero); // { data: <...>, model: <...>, ... }});
6th of June, 2015
Generator - Basics
async function loadHero(){ var hero = {};
try { hero.data = await httpGet('/characters/hero.json'); hero.model = await httpGet(hero.data.modelUrl); hero.material = await httpGet(hero.model.materialUrl); } catch (error) { console.log(error); hero = null; }
return hero;}
loadHero().then(function () { console.log(hero); // { data: <...>, model: <...>, ... }});
6th of June, 2015
Generator - Browser support
● Generator are ES6
● Async functions are ES7
● Use them today with transpilers:https://github.com/google/traceur-compilerhttps://babeljs.io/
6th of June, 2015
Thanks for listening!
References:
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Promise
https://www.promisejs.org/
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Instructions/function*
https://github.com/lukehoban/ecmascript-asyncawait
6th of June, 2015
Join the community !(in Paris)
Social networks :● Follow us on Twitter : https://twitter.com/steamlearn● Like us on Facebook : https://www.facebook.com/steamlearn
SteamLearn is an Inovia initiative : inovia.fr
You wish to be in the audience ? Join the meetup group! http://www.meetup.com/Steam-Learn/