場景:想請求量較大的網絡數據,好比想獲取1000條結果,但數據處理速度慢,有超時的風險,能夠分紅10次處理,每次處理100條;全部請求完成後再統一進行處理。git
這樣的應用場景,能夠這樣處理:github
// 模擬網絡請求 function fetch(url, callback) { setTimeout(function (){ callback(null, { subjects: [{ data: Math.round(Math.random() * 100) }] }); }, 2000); } // 實現方案1 function multiTask_1 () { var arr = []; var baseUrl = 'https://api.douban.com/v2/movie/top250'; for (var start = 0; start < 10; start++) { var url = baseUrl + '?start=' + start + "&count=1"; fetch(url, function(error, res) { var data = res.subjects; arr = arr.concat(data); // 調用完成後統一處理 if (arr.length === 10) { console.log(arr); } }); } }
將運行結果用arr.length來判斷,若是arr.length不像咱們指望的那樣,好比因爲網絡傳輸或者處理異常,少一條,那麼咱們將沒法作後續的處理。這種處理方式強業務耦合;不具備普適性。api
// 方案2 function multiTask_2 () { var taskWatcher = 0; var arr = []; var baseUrl = 'https://api.douban.com/v2/movie/top250'; for (var start = 0; start < 10; start++) { taskWatcher++; var url = baseUrl + '?start=' + start + "&count=1"; fetch(url, function(error, res) { var data = res.subjects; arr = arr.concat(data); taskWatcher--; if (taskWatcher === 0) { console.log(arr); } }); } }
方案2 的判斷條件,這裏的 taskWatcher 充當異步任務執行狀況的觀察員,
僅與異步過程的調用次數有關,且與其餘處理過程無關。那有沒有其餘方案呢數組
Promise.all(iterable) 方法返回一個 Promise, 它將在上述可迭代對象中的全部 Promise 被 resolve 以後被 resolve,或者在任一 Promise 被 reject 後被 reject。網絡
function multiTask_3 () { // var taskWatcher = 0; var taskStack = []; var arr = []; var baseUrl = 'https://api.douban.com/v2/movie/top250'; for (var start = 0; start < 10; start++) { taskStack.push( new Promise((resolve, reject) => { var url = baseUrl + '?start=' + start + "&count=1"; fetch(url, function(error, res) { var data = res.subjects; arr = arr.concat(data); resolve(); }); }) ); } Promise.all(taskStack).then(function () { console.log(arr); }); }
這種方式更具備通用性,若是異步任務類型不一樣,也能夠用這種方式來解決。不過應當注意reject的處理。避免其對最終處理的影響。dom
EventProxy是樸靈寫的,https://github.com/JacksonTian/eventproxy異步
var ep = new EventProxy(); var arr = []; ep.after('fetchData', 10, function (list) { list.forEach(function(item){ arr = arr.concat(item); }); console.log(arr); }); var baseUrl = 'https://api.douban.com/v2/movie/top250'; for (var start = 0; start < 10; start++) { var url = baseUrl + '?start=' + start + "&count=1"; fetch(url, function(error, res) { var data = res.subjects; ep.emit('fetchData', data); }); }
EventProxy基於事件訂閱/發佈模式,這裏的after 方法能夠偵聽屢次事件,回調中保存了屢次異步任務的數據結果的數組;除此以外EventProxy還支持多個不一樣事件的偵聽和處理。fetch