異步操做git
程序裏面全部的任務,能夠分紅兩類:同步任務(synchronous)和異步任務(asynchronous)github
JavaScript 運行時,除了一個正在運行的主線程,引擎還提供一個任務隊列(task queue),編程
裏面是各類須要當前程序處理的異步任務。(實際上,根據異步任務的類型,存在多個任務隊列。爲了方便理解,這裏假設只存在一個隊列。)數組
f1
和f2
,編程的意圖是f2
必須等到f1
執行完成,才能執行
function f1() { // ... } function f2() { // ... } f1(); f2();
上面代碼的問題在於,若是f1
是異步操做,f2
會當即執行,不會等到f1
結束再執行瀏覽器
f1
,把f2
寫成f1
的回調函數
function f1(callback) { // ... callback(); } function f2() { // ... } f1(f2);
f1.on('done', f2); // 當 f1 發生 done 事件,就執行 f2
對f1
進行改寫:服務器
function f1() { setTimeout(function () { // ... f1.trigger('done'); // 表示,執行完成後,當即觸發 事件,從而開始執行 }, 1000); }donef2
jQuery.subscribe('done', f2);
function f1() { setTimeout(function () { // ... jQuery.publish('done'); }, 1000); }
f1 執行完成後,向信號中心 jQuery 發佈 done 信號,從而引起 f2 的執行網絡
jQuery.unsubscribe('done', f2);
var items = [ 1, 2, 3, 4, 5, 6 ]; var results = []; function async(arg, callback) { console.log('參數爲 ' + arg +' , 1秒後返回結果'); setTimeout(function () { callback(arg * 2); }, 1000); } function final(value) { console.log('完成: ', value); } function series(item) { if(item) { async( item, function(result) { results.push(result); return series(items.shift()); }); } else { return final(results[results.length - 1]); } } series(items.shift());
var items = [ 1, 2, 3, 4, 5, 6 ]; var results = []; function async(arg, callback) { console.log('參數爲 ' + arg +' , 1秒後返回結果'); setTimeout(function () { callback(arg * 2); }, 1000); } function final(value) { console.log('完成: ', value); } items.forEach(function(item) { async(item, function(result){ results.push(result); if(results.length === items.length) { final(results[results.length - 1]); } }) });
forEach
方法會同時發起六個異步任務,等到它們所有完成之後,纔會執行 final
函數
n
個異步任務,這樣就避免了過度佔用系統資源。
var items = [ 1, 2, 3, 4, 5, 6 ]; var results = []; var running = 0; var limit = 2; function async(arg, callback) { console.log('參數爲 ' + arg +' , 1秒後返回結果'); setTimeout(function () { callback(arg * 2); }, 1000); } function final(value) { console.log('完成: ', value); } function launcher() { while(running < limit && items.length > 0) { var item = items.shift(); async(item, function(result) { results.push(result); running--; if(items.length > 0) { launcher(); } else if(running == 0) { final(results); } }); running++; } } launcher();
上面代碼中,最多隻能同時運行兩個異步任務。變量 running 記錄當前正在運行的任務數,只要低於門檻值,就再啓動一個新的任務,若是等於 0,就表示全部任務都執行完了,這時就執行 final() 函數。多線程