短小強悍的JavaScript非同步呼叫庫
對於博文 20行完成一個JavaScript模板引擎 的備受好評我感到很驚訝,並決定用此文章介紹使用我經常使用的另一個小巧實用的工具.我們知道,在瀏覽器中的 JavaScript 絕大部分的操作都是非同步的(asynchronous),所以我們一直都需要使用回撥方法,而有時不免陷入回撥的泥淖而欲死欲仙。
假設我們有兩個 functions ,我們順序地在一個後面執行完後呼叫另一個。他們都操作同一個變數。第一個設定它的值,第二個使用它的值。
var value; var A = function() { setTimeout(function() { value = 10; }, 200); } var B = function() { console.log(value); }
那麼,現在如果我們執行 A();B(); 我們將在控制檯看到輸出為 undefined . 之所以會這樣是因為 A 函式使用了非同步方式設定 value 。我們能做的就是傳一個回撥函式給A,並讓函式A在執行完後執行回撥函式。
var value; var A = function(callback) { setTimeout(function() { value = 10; callback(); }, 200); }; var B = function() { console.log(value); }; A(function() { B(); });
這樣確實有用,但想象一下加入我們需要執行5個或更多方法時將會發生什麼。一直傳遞迴調函式將會導致混亂和非常不雅觀的程式碼。
好的解決辦法是寫一個工具函式,接受我們的程式並控制整個過程。讓我們先從最簡單的開始:
var queue = function(funcs) { // 接下來請看,董卿??? }
接著,我們要做的是通過傳遞A和B來執行該函式 - queue([A, B])。我們需要取得第一個函式並執行它。
var queue = function(funcs) { var f = funcs.shift(); f(); }
如果執行這段程式碼,您將看到一個 TypeError: undefined is not a function。這是因為 A函式沒收到回撥引數但卻試圖執行它。讓我們換一種呼叫方法。
var queue = function(funcs) { var next = function() { // ... }; var f = funcs.shift(); f(next); };
在 A執行完後會呼叫 next 方法。將下一步操作放在 next 函式列表中是個很好的做法。我們可以將程式碼歸攏在一起,而且我們能夠傳遞整個陣列(即便陣列中有很多函式等待執行)。
var queue = function(funcs) { var next = function() { var f = funcs.shift(); f(next); }; next(); };
到了這一步,我們基本上達到了我們的目標。即函式A 執行後,接著會呼叫 B,列印出變數的正確值。這裡的關鍵是 shift 方法的使用。它刪除陣列的第一個元素並返回該元素。一步一步執行下去, funcs陣列就會變成 empty(空的)。所以,這可能會導致另一個錯誤。為了證明這一觀點,讓我們假設我們仍然需要執行這兩個功能,但我們不知道他們的順序。在這種情況下,兩個函式都應該接受回撥引數(callback )並執行它。
var A = function(callback) { setTimeout(function() { value = 10; callback(); }, 200); }; var B = function(callback) { console.log(value); callback(); };
當然,我們會得到 TypeError: undefined is not a function.
要阻止這一點,我們應該檢查funcs陣列是否為空。
var queue = function(funcs) { (function next() { if(funcs.length > 0) { var f = funcs.shift(); f(next); } })(); };
我們所做的就是定義 next 函式並呼叫它。這種寫法減少了一點程式碼。
讓我們試著想象儘可能多的情況。比如當前執行功能的 scope 。函式內的 this 關鍵字可能指向了全球的 window 物件。,如果我們可以設定自己的scope 當然是件很酷的事情。
var queue = function(funcs, scope) { (function next() { if(funcs.length > 0) { var f = funcs.shift(); f.apply(scope, [next]); } })(); };
我們為這個tiny 類庫增加了一個引數。接著我們使用 apply 函式,而不是直接呼叫 f(next),來設定scope 並將引數 next 傳遞進去。同樣的功能,但漂亮多了。
我們需要的最後一個特性,就是是函式間傳遞引數的能力。當然我們不知道具體會有多少引數將被使用。這就是為什麼我們需要使用 arguments 變數的原因。你可能知道,該變數在每個 JavaScript函式中都是可用的,代表了傳進來的引數。它就和一個陣列差不多,但不完全是。因為在 apply 方法中我們需要使用真正的陣列,使用一個小竅門來進行轉換。
var queue = function(funcs, scope) { (function next() { if(funcs.length > 0) { var f = funcs.shift(); f.apply(scope, [next].concat(Array.prototype.slice.call(arguments, 0))); } })(); };
下面是測試的程式碼:
// 測試程式碼 var obj = { value: null }; queue([ function(callback) { var self = this; setTimeout(function() { self.value = 10; callback(20); }, 200); }, function(callback, add) { console.log(this.value + add); callback(); }, function() { console.log(obj.value); } ], obj);
執行後的輸出為:
30 10
為了程式碼的可讀性和美觀,我們將部分相關的程式碼移到一行內:
var queue = function(funcs, scope) { (function next() { if(funcs.length > 0) { funcs.shift().apply(scope || {}, [next].concat(Array.prototype.slice.call(arguments, 0))); } })(); };
你可以 點選這裡檢視並除錯相關程式碼 ,完整的測試程式碼如下:
var queue = function(funcs, scope) { (function next() { if(funcs.length > 0) { funcs.shift().apply(scope || {}, [next].concat(Array.prototype.slice.call(arguments, 0))); } })(); }; var obj = { value: null }; queue([ function(callback) { var self = this; setTimeout(function() { self.value = 10; callback(20); }, 200); }, function(callback, add) { console.log(this.value + add); callback(); }, function() { console.log(obj.value); } ], obj);
原文出處: krasimirtsonev
相關文章
- python自帶效能強悍的標準庫 itertoolsPython
- 新人必看的短小而精悍的javascript functionJavaScriptFunction
- JavaScript非同步呼叫的發展歷程JavaScript非同步
- 多執行緒非同步日誌系統,高效、強悍的實現方式:雙緩衝!執行緒非同步
- 強悍的 ubuntu —— 視窗介面管理與設定Ubuntu
- 超級強悍的下載之工具curl(轉)
- 短小精悍的釋出訂閱庫 mittMIT
- 200多種Android動畫效果的強悍框架Android動畫框架
- Bootstrap:簡潔、直觀、強悍的前端開發框架boot前端框架
- 冰點密碼破解 — 強悍的偵錯程式 SOFTICE密碼
- 細數電腦史上10大強悍黑客黑客
- 雷神Dino遊戲本評測:強悍的效能,今晚吃雞遊戲
- 同步、非同步、阻塞、非阻塞的區別非同步
- 同步非同步,阻塞非阻塞非同步
- 非同步、同步、阻塞、非阻塞非同步
- 同步、非同步、阻塞、非阻塞非同步
- 非同步呼叫和同步呼叫 及 spring的@Async註解非同步Spring
- IO - 同步 非同步 阻塞 非阻塞的區別非同步
- 同步、非同步、阻塞、非阻塞的簡單理解非同步
- 同步與非同步、阻塞與非阻塞的理解非同步
- 最強悍LoadRunner和瀏覽器相容完美攻略瀏覽器
- 同步非同步 與 阻塞非阻塞非同步
- 理解阻塞、非阻塞、同步、非同步非同步
- 同步、非同步,阻塞、非阻塞理解非同步
- 同步、非同步、阻塞與非阻塞非同步
- 同步、非同步、阻塞和非阻塞非同步
- Dubbo原始碼分析(十)同步呼叫與非同步呼叫原始碼非同步
- JavaScript呼叫ActiveX操作Oracle資料庫JavaScriptOracle資料庫
- 同步阻塞、同步非阻塞、多路複用的介紹
- 諾基亞安卓旗艦機外觀配置曝光:效能強悍安卓
- 紅米3S詳細評測 續航能力強悍
- [轉]阻塞/非阻塞與同步/非同步非同步
- 同步與非同步 阻塞與非阻塞非同步
- RFC 同步非同步呼叫例項非同步
- java同步非阻塞IOJava
- 非同步和非阻塞非同步
- .NET非同步方法呼叫的例子非同步
- 真正的 Tornado 非同步非阻塞非同步