+ - 0:00:00
Notes for current slide
Notes for next slide

Async in JavaScript

Yeechan Lu

1 / 65

エーシンク(ēshinku)イン(in)ジャーバスクリップト(jābasukuripputo)

イェーチャン・ルー

2 / 65

Async(eɪˈsɪŋk) in(ɪn) JavaScript(ˈdʒɑːvəˌskrɪpt)

Yeechan Lu

3 / 65

Concurrency(并发)

使多个操作可以在重叠的时间段内进行

4 / 65

Parallelism(并行)

----------------▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇-----
--▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇----------------------------------------
----------------------------▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇---
5 / 65

Coroutine(协程)

▇▇▇▇▇▇▇▇--------▇▇▇▇▇▇▇▇▇-----------------▇▇▇▇--------▇▇▇▇▇▇▇▇-
--------▇▇▇▇▇▇▇▇---------▇▇▇▇▇▇▇▇▇------------▇▇▇▇▇▇▇▇---------
----------------------------------▇▇▇▇▇▇▇▇---------------------
6 / 65

node has non-blocking IO everywhere

— Tim Caswell

7 / 65

Single Thread (v8), Event Driven

8 / 65

Single-threaded Concurrency

9 / 65

Coroutine!

10 / 65

node has non-blocking IO everywhere

∴coroutine is requred everywhere

11 / 65

Continuable

12 / 65

In Dark Ages...

13 / 65

synchronous

// synchronous
function test_and_load(filename) {
var stat = fs.statSync(filename);
// Filter out non-files
if (!stat.isFile()) { return; }
// Otherwise read the file in
return fs.readFileSync(filename)
}
15 / 65

synchronous

seperate cb

// simple continuable with seperate callback and errback
function test_and_load(filename) { return function (callback, errback) {
fs.stat(filename)(function (stat) {
// Filter out non-files
if (!stat.isFile()) { callback(); return; }
// Otherwise read the file in
fs.readFile(filename)(callback, errback);
}, errback);
}}
16 / 65

synchronous

seperate cb

combined cb

// simple continuable with single combined callback
function test_and_load(filename) { return function (callback) {
fs.stat(filename)(function (stat) {
// Pass along any errors before we do anything
if (stat instanceof Error) { callback(stat); return; }
// Filter out non-files
if (!stat.isFile()) { callback(); return; }
// Otherwise read the file in
fs.readFile(filename)(callback);
});
}}
17 / 65

synchronous

seperate cb

combined cb

inimino

// inimino style continuables
function test_and_load(filename) { return function (cont) {
fs.stat(filename)(rightContinuation(cont)(function (stat) {
// Filter out non-files
if (!stat.isFile()) { cont(); return; }
// Otherwise read the file in
fs.readFile(filename)(cont);
}));
}}
18 / 65

synchronous

seperate cb

combined cb

inimino

continuables

// http://github.com/bentomas/node-continuables
function test_and_load(filename) {
return fs.stat(filename)(function (stat) {
// Pass along any errors before we do anything
if(stat instanceof Error) { return; }
// Filter out non-files
if (!stat.isFile()) { return null; }
// Otherwise read the file in
return fs.readFile(filename);
});
}
19 / 65

synchronous

seperate cb

combined cb

inimino

continuables

node-promise

// promise based with node-promise helpers (github.com/kriszyp/node-promise)
var when = require("promise").when;
function test_and_load(filename) {
return when(fs.stat(filename), function (stat) {
// Filter out non-files
if (!stat.isFile()) { return; }
// Otherwise read the file in
return fs.readFile(filename);
});
}
20 / 65

synchronous

seperate cb

combined cb

inimino

continuables

node-promise

patch-promise

// promise based with CommonJS monkey patch (github.com/kriszyp/node-commonjs/blob/master/patch-promise.js)
function test_and_load(filename) {
return fs.stat(filename).then(function (stat) {
// Filter out non-files
if (!stat.isFile()) { return; }
// Otherwise read the file in
return fs.readFile(filename);
});
}
21 / 65

synchronous

seperate cb

combined cb

inimino

continuables

node-promise

patch-promise

promise based

// promise based (how it works in current node)
function test_and_load(filename) {
var promise = new process.Promise();
fs.stat(filename).addCallback(function (stat) {
// Filter out non-files
if (!stat.isFile()) { promise.emitSuccess(); return; }
// Otherwise read the file in
fs.readFile(filename).addCallback(function (data) {
promise.emitSuccess(data);
}).addErrback(function (error) {
promise.emitError(error);
});
}).addErrback(function (error) {
promise.emitError(error);
});
return promise;
}
22 / 65
method(arg0, arg1, arg2, function (error, result0, result1) {
puts('complete');
});
24 / 65

Callback Ages

25 / 65
function doGreatWork(userId, fileName, callback) {
getUser(userId, function (err, user) {
if (err) return callback(err, null);
getCompany(user.companyId, function (err, company) {
if (err) return callback(err, null);
getLocation(company.location, function (err, location) {
if (err) return callback(err, null);
getLatLong(location, function (err, latLong) {
if (err) return callback(err, null);
findSatelitteImage(latLong, 5 * km, function (err, imageUrl) {
if (err) return callback(err, null);
downloadImage(imageUrl, function (err, image) {
if (err) return callback(err, null);
writeToFile(fileName, image, function (err, result) {
if (err) return callback(err, null);
return callback(null, fileName)
});
});
});
});
});
});
});
}
26 / 65

By following this scheme everywhere, I'm confident that very good user-land deferred / promise / continuation libraries will spring up.

— Ryan Dahl

27 / 65

libraries will spring up

28 / 65

29 / 65

30 / 65

31 / 65

32 / 65

33 / 65

34 / 65

Let's talk about Promise

35 / 65
method(arg0, arg1, arg2).then(function(result) {
puts('complete');
}).catch(function(error) {
puts('failed');
})
36 / 65
function doGreatWork(userId, fileName) {
return getUser(userId).then(function (user) {
return getCompany(user.companyId)
}).then(function(company) {
return getLocation(company.location)
}).then(function(location) {
return getLatLong(location)
}).then(function(latLong) {
return findSatelitteImage(latLong, 5 * km)
}).then(function(imageUrl) {
return downloadImage(imageUrl)
}).then(function(image) {
return writeToFile(fileName, image)
}).then(function() {
return fileName;
})
}
37 / 65

Looks great?

38 / 65
function doGreatWork(userId, fileName) {
return getUser(userId).then(function (user) {
return getCompany(user.companyId)
}).then(function(company) {
/* I need user here */
})
}
39 / 65
function doGreatWork(userId, fileName) {
return getUser(userId).then(function (user) {
return getCompany(user.companyId).then(function(company) {
return user.sayHello(company);
})
})
}
40 / 65

🤣

41 / 65
function doGreatWork(userId, fileName) {
var _user;
return getUser(userId).then(function (user) {
_user = user;
return getCompany(user.companyId)
}).then(function(company) {
return _user.sayHello(company);
})
}
42 / 65
function doGreatWork(userId, fileName) {
var ctx = {};
return getUser(userId).then(function (user) {
ctx.user = user;
return getCompany(user.companyId)
}).then(function(company) {
return ctx.user.sayHello(company);
})
}
43 / 65
# CoffeeScript
do_great_work = (file_name) ->
get_user(user_id).then (@user) =>
get_company(@user.company_id)
.then (@company) =>
@user.say_hello(@company)
44 / 65
// Bluebird
function doGreatWork(userId, fileName) {
return getUser(userId).bind({}).then(function (user) {
this.user = user;
return getCompany(user.companyId)
}).then(function(company) {
return this.user.sayHello(company);
}).bind()
}
45 / 65

Meanwhile...

46 / 65
function doLittleWork(name) {
return uploadHighScore(getDeviceId(), name, name.length)
.then(() => true)
.catch(() => false)
}
doLittleWork("orzFly").then(() => saveAndQuit());
47 / 65
function doLittleWork(name) {
return uploadHighScore(getDeviceId(), name, name.length)
.then(() => true)
.catch(() => false)
}
doLittleWork(undefined).then(() => saveAndQuit());
// TypeError: Cannot read property 'length' of undefined
// at doLittleWork (presentation.js:6:51)
48 / 65

🤣

49 / 65

Generator!

50 / 65

Promise with Generator

51 / 65
co(function* () {
try {
let result = yield method(arg0, arg1, arg2);
puts('complete');
} catch (error) {
puts('failed');
})
})
52 / 65
var doGreatWork = co.wrap(function* (userId, fileName) {
var user = yield getUser(userId);
var company = yield getCompany(user.companyId);
var location = yield getLocation(company.location);
var latLong = yield getLatLong(location);
var imageUrl = yield findSatelitteImage(latLong, 5 * km);
var image = yield downloadImage(imageUrl);
yield writeToFile(fileName, image);
return fileName;
});
53 / 65

Bluebird.coroutine

54 / 65
var doGreatWork = Promise.coroutine(function* (userId, fileName) {
var user = yield getUser(userId);
var company = yield getCompany(user.companyId);
var location = yield getLocation(company.location);
var latLong = yield getLatLong(location);
var imageUrl = yield findSatelitteImage(latLong, 5 * km);
var image = yield downloadImage(imageUrl);
yield writeToFile(fileName, image);
return fileName;
});
55 / 65

async & await

56 / 65
var doGreatWork = async function (userId, fileName) {
var user = await getUser(userId);
var company = await getCompany(user.companyId);
var location = await getLocation(company.location);
var latLong = await getLatLong(location);
var imageUrl = await findSatelitteImage(latLong, 5 * km);
var image = await downloadImage(imageUrl);
await writeToFile(fileName, image);
return fileName;
};
57 / 65
var doGreatWork = async function (userId, fileName) {
let user = getUser(userId);
let company = yield getCompany(user.companyId);
return yield user.sayHello(company);
};
58 / 65
var doLittleWork = async function (userId, fileName) {
try {
yield uploadHighScore(getDeviceId(), name, name.length);
return true;
} catch (e) {
return false;
}
};
doLittleWork(undefined).then(() => saveAndQuit());
59 / 65

60 / 65

One more thing...

61 / 65

62 / 65
new Thread(function() { console.log("Hello, threads!"); });
let result = new Thread(() => 42).join(); // returns 42
new Thread(() => 42).asyncJoin().then((result) => /* result is 42 */)
63 / 65

The next step for this wild thought experiment is to attempt to implement it and see if it works.

64 / 65

Q&A

65 / 65

エーシンク(ēshinku)イン(in)ジャーバスクリップト(jābasukuripputo)

イェーチャン・ルー

2 / 65
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow