哦,代码……就把它们当做插图吧
跟着 CPU 从单核变多核,软件从注意功能到注意体验,Web 从页面跳转体式格局到 Web2.0 的无革新加载(AJAX),顺序员越来越多的打仗多线程和异步。而 Android 的主线程中不允许操纵收集,更是将顺序员们推向了异步的深渊。异步深渊发生的重要原因是回调,这在 nodejs 里特别严峻。
// [node.js]
doFirstThing(function(err, data) {
doSecondThing(data, function(err, data) {
doThirdThing(data, function(err, data) {
// ... fall down
})
});
});
为了逃离回调的深渊,人人最先想种种要领来把回调扁平化。
在 JavaScript 中,Promise(指该类要领而非某个库)成为浩瀚解决计划的佼佼者,并胜利被 ES6 采用。
// [node.js]
doFirstThing()
.then(doSecondThing)
.then(doThirdThing)
// .then(...) - continuous
.catch(function() {
// something wrong
});
而 C# 则经由过程 Task 和 ThreadPool 让异步编程变得轻易。前面议论的 C# 并行计算(Parallel 和 ParallelQuery) 就是基于 Task 的。不过运用 Task.ContinueWith()
和 Parallel.ForEach()
的时刻,就会以为:这不就是 Promise 吗?
// [csharp]
Task.Run(() => {
// do first thing and return a data
return "first";
}).ContinueWith(task => {
// do second thing and return a data
return new []{ task.Result, "second" };
}).ContinueWith(task => {
// do final thing
foreach (string s in task.Result) { Console.WriteLine(s); }
}).Wait();
以后 C#5.0 又推出 async/await
计划,将异步代码写得像同步代码一样,由编译器来将 async/await
代码封装成异步 Task 体式格局,而不是由人工处置惩罚,这大大下降了写异步顺序的门坎。
// [csharp]
private async static Task Process() {
string first = await Task.Run(() => "first");
string[] all = await Task.Run(() => {
return new [] { first, "second" };
});
await(Task.Run(() => {
foreach (string s in all) { Console.WriteLine(s); }
}));
}
JavaScript 顺序员们一边在等着 ES7 的 async/await
特征,一边也没闲着,在 ES6 generator/yield
特征基础上开发了个 co 出来,供应了类似于 async/await
特征的异步编程体式格局。
// [node.js]
var co = require("co");
co(function*() {
var first = yield new Promise(function(resolve) {
setTimeout(function() {
resolve("first");
}, 100);
});
var all = yield new Promise(function(resolve) {
setTimeout(function() {
resolve([first, "second"])
}, 200);
})
console.log(all);
});
// [ 'first', 'second' ]
不过 co 顺序写起来又要写 Generator,又要用 yeild,还经常要封装 Promise,代码依然不够简约。现在 async/await 已经在 TypeScript、Babel、Node 7.6+ 等环境中获得支撑,运用 JavaScript 的 async/await 不仅能大大简化代码,还能下降逻辑思绪的复杂度。
2018.1.18 更新,由于 async/await 早已进入实践阶段