哦,代碼……就把它們當(dāng)成插圖吧
隨著 CPU 從單核變多核,軟件從注重功能到注重體驗,Web 從頁面跳轉(zhuǎn)方式到 Web2.0 的無刷新加載(AJAX),程序員越來越多的接觸多線程和異步。而 Android 的主線程中不允許操作網(wǎng)絡(luò),更是將程序員們推向了異步的深淵。異步深淵產(chǎn)生的主要原因是回調(diào),這在 nodejs 里尤其嚴重。
// [node.js]
doFirstThing(function(err, data) {
doSecondThing(data, function(err, data) {
doThirdThing(data, function(err, data) {
// ... fall down
})
});
});
為了逃離回調(diào)的深淵,大家開始想各種辦法來把回調(diào)扁平化。
在 JavaScript 中,Promise(指該類方法而非某個庫)成為眾多解決方案的佼佼者,并成功被 ES6 采納。
// [node.js]
doFirstThing()
.then(doSecondThing)
.then(doThirdThing)
// .then(...) - continuous
.catch(function() {
// something wrong
});
而 C# 則通過 Task 和 ThreadPool 讓異步編程變得容易。前面談?wù)摰?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
特性基礎(chǔ)上開發(fā)了個 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 程序?qū)懫饋碛忠獙?Generator,又要用 yeild,還常常要封裝 Promise,代碼仍然不夠簡潔。所以繼續(xù)期待 ES7 的 async/await
特性。
更多建議: