閉包的應用Ajax
來自專欄 花生的日常問題的起源來自知乎裡面的一篇文章,裡面提到的一個面試題
某個應用模塊由文本框 input,以及按鈕 A,按鈕 B 組成。點擊按鈕 A,會向地址 urlA 發出一個 ajax 請求,並將返回的字元串填充到 input 中(覆蓋 input 中原有的數據),點擊按鈕 B,會向地址 urlB 發出一個 ajax 請求,並將返回的字元串填充到 input 中(覆蓋 input 中原有的數據)。
當用戶依次點擊按鈕 A、B 的時候,預期的效果是 input 依次被 urlA、urlB 返回的數據填充,但是由於到 urlA 的請求返回比較慢,導致 urlB 返回的數據被 urlA 返回的數據覆蓋了,與用戶預期的順序不一致。
請問如何設計代碼,解決這個問題?
很顯然,我們需要一個能長期保存下來的變數來確定前一個ajax請求是否完成,所以這個時候我們需要用到閉包,
- 設置一個變數idle長期存儲在內存中,判斷當前是否在處理ajax請求,
- 設置一個數組cache來緩存後面被阻塞的ajax請求,每次請求執行時拿出cache裡面的值進行使用並刪除
- 設置一個run方法來執行這些請求
$.ajax = (function(_ajax){ var idle = true,cache = []; function run(){ if(!idle) return false; var arg = cache.shift(), idle = false; _ajax(arg); } return function(){ cache.push(arguments); run(); }})($.ajax)
- 重寫arguments內的success,error方法,先調用之前相應的success,error方法,然後繼續調用cache裡面的方法,如果cache為空則不停止執行
- 執行ajax方法
function run(){ if(!(idle||cache.length)) return false; var arg = cache.shift(), _success = arg.success; _error = arg.error; idle = false; arg.success = function(){ _success.apply(this,arguments); idle = true; run(); }; arg.error = function(){ _error.apply(this,arguments); idle = true; run(); }; _ajax(arg); }
最後,我們發現success和error有相同的部分,我們把它提出來,以下是完整版本
$.ajax = (function(_ajax){ var idle = true,cache = []; function run(){ if(!(idle||cache.length)) return false; var arg = cache.shift(), _success = arg.success; _error = arg.error; idle = false; arg.success = function(){ _success.apply(this,arguments); next(); }; arg.error = function(){ _error.apply(this,arguments); next(); }; _ajax(arg); } function next(){ idle = true; run(); } return function(){ cache.push(arguments); run(); }})($.ajax)
推薦閱讀:
※怎樣合理地使用 Ajax ?過度使用 Ajax 會有哪些弊端?
※phamtomjs能否得到js運行後的代碼並輸出到文檔?
※訪問localhost和127.0.0.1是否完全一樣?
※115登錄頁的long polling在chrome裡面為什麼看不到返回結果?
※怎樣防止重複發送 Ajax 請求?