回調(diào),是每個(gè)nodejser必須面對(duì)的問(wèn)題,社區(qū)也有很多解決方案,諸如asnyc,promise和ECMAScript 第六版的引入。異步的那些事兒,講會(huì)圍繞這三個(gè)方案來(lái)展開(kāi)。
async
項(xiàng)目地址:https://github.com/caolan/async
async是最早在node.js社區(qū)流行的異步庫(kù),其簡(jiǎn)單的語(yǔ)法和相對(duì)綠色的封裝,深受node.jser所愛(ài),也是本人最常用的異步庫(kù)。
相信語(yǔ)法這種東西,文檔會(huì)比我描述得更詳細(xì),本文不會(huì)過(guò)多地介紹語(yǔ)法問(wèn)題,側(cè)重實(shí)現(xiàn)原理。下面將以幾個(gè)本人認(rèn)為比較經(jīng)典的例子作為展開(kāi)。
async核心代碼
// assuming openFiles is an array of file names and saveFile is a function
// to save the modified contents of that file:
async.each(openFiles, saveFile, function(err){
// if any of the saves produced an error, err would equal that error
});
上面的函數(shù),會(huì)遍歷openFiles的數(shù)組,對(duì)文件進(jìn)行讀取,當(dāng)全部文件內(nèi)容都讀取完畢后,執(zhí)行最后的回調(diào)函數(shù)。
async.each = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
_each(arr, function (x) {
iterator(x, only_once(done) );
});
function done(err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback();
}
}
}
};
async.each(openFiles, saveFile, callback) 讀取openFiles的數(shù)組長(zhǎng)度,創(chuàng)建completed作為哨兵變量,每完成一件saveFile任務(wù)后,completed 自增1,當(dāng) completed 的大小等于 openFiles 的數(shù)組長(zhǎng)度的時(shí)候,代表任務(wù)結(jié)束,回調(diào)函數(shù)。
實(shí)現(xiàn)非常簡(jiǎn)單,本人也實(shí)現(xiàn)了一個(gè)版本,可以參考一下。
var fs = require('fs');
async = {
map: function (arrs, iter, callback) {
var length = arrs.length;
var count = 0; //哨兵變量
var result = []; //結(jié)果緩存
var next = function (err, data) {
if (err) {
return callback(err); // 遇到錯(cuò)誤馬上跳出
}
result.push(data);
count += 1;
if (count === length) {
return callback(err, result);
}
};
arrs.forEach(function (arr) {
iter.call(null, arr, next);
})
}
};
async.map(['1.txt', '2.txt', '3.txt'], function (filename, next) {
fs.readFile(filename, 'utf-8', next);
}, function (err, result) {
console.log(result);
console.log('fin');
});
源碼:
https://github.com/youyudehexie/nodejs-cookbook/blob/master/async/demo1.js