摘要:上篇文章中講到,使用的方法操作請求,會受到回調函數嵌套的問題。第一次回調第二次回調內部實現上,和都是基于實現的對于多個同時請求,共同執行同一個回調函數這一點上,有一個方法,接受多個對象實例,同時執行。
上篇文章中講到,使用jquery的ajax方法操作ajax請求,會受到回調函數嵌套的問題。當然,jquery團隊也發現了這個問題,在2011年,也就是jquery 1.5版本之后,jQuery.Deferred對象為解決這類問題應運而出。之后,zapto等框架也推出相同api的deferred對象,來進行異步操作。
在jquery 1.5 版本之后,ajax請求的內部實現被重寫。$.ajax方法返回的不再是一個jqXHR對象,而是一個Deferred對象。
使用jquery 1.5版本之后的代碼,可以用下面的方法進行一次ajax請求。
// 前提引入jquery var fetchData = function (url) { return $.ajax({ type: "get", url: url }); }
這樣一次請求的內容就已經完成,$.ajax返回一個$.Deferred對象,那么我們就可以使用$.Deferred對象的api進行一些異步操作。
出于篇幅,這里只簡單進行介紹.done,.fail,.then和$.when這三個方法。
對于每一個$.Deferred對象來說,實例有多個方法,其中done方法代表異步完成時執行的方法,fail代表異步失敗時執行的方法,這兩個方法同時仍舊返回一個$.Deferred對象的實例。
繼續上面的ajax操作,我們可以這樣寫成功和失敗的回調:
// fetchData 接上 fetchData() //執行函數返回一個Deferred對象實例 .done() //接受一個函數,ajax請求成功調用 .fail() //接受一個函數,ajax請求失敗調用 .done() //第二個成功狀態的回調方法 .fail()
同樣的對于.then方法,接受兩個函數,第一個代表成功時執行的方法,第二個代表失敗時的執行方法。同樣的,它也返回一個deferred對象實例。意味著也能進行連綴調用。
fetchData() .then(successFn, errorFn) //第一次回調 .then(successFn, errorFn) //第二次回調
內部實現上,.done 和 .fail 都是基于 .then實現的
fetchData() fetchData() .done(successFn) <===> .then(successFn, null) .fail(errorFn) <===> .then(null, errorFn)
對于多個ajax同時請求,共同執行同一個回調函數這一點上,jquery有一個$.when方法,接受多個Deferred對象實例,同時執行。
var fetchData = function (url) { return $.ajax({ type: "get", url: url }); } var fetchData1 = fetchData("/path/to/data1"); var fetchData2 = fetchData("/path/to/data2"); $.when(fetchData1, fetchData2, function (data1, data2) { // fetchData1 響應為data1 // fetchData2 響應為data2 })
完美解決了開發中的異步問題。
上面的$.ajax只是在$.deferred對象上封裝了一層ajax操作。實際上,真正的$.Deferred對象是這樣調用的:
function printA () { var deferred = new $.Deferred(); setTimeout(function () { console.log("A"); deferred.resolve(" is done."); }, 1000); return deferred; } function printB (msg) { var deferred = new $.Deferred(); setTimeout(function () { console.log("B" + msg); deferred.resolve(); }, 1000); return deferred; } printA() .then(printA) .then(printB)
每個函數維護一個Deferred對象,在每一個具有異步操作的函數執行成功后,指示全局deferred對象執行下一個函數,達到異步的效果。
新建完成$.Deferred實例deferred之后,調用deferred.resolve()代表成功完成響應,deferred.reject()即代表調用失敗響應。
詳細解釋源碼請參見另一篇文章,這里我們主要寫一下這種調用方式實現的tiny版。
首先我們寫一個Callback對象維護我們的回調函數隊列
var Callbacks = function () { function Callbacks () { this.callbacks = []; } Callbacks.prototype.add = function (fn) { this.callbacks.add(fn); return this; } Callbacks.prototype.fire = function () { var len = this.callbacks.length; if(len) { this.callbacks.unshift()(); } } return Callbacks; }
這段代碼邏輯很簡單,Callbacks對象有兩個方法,分別是add和fire,調用add則向當前的callbacks數組內新增一個function。fire方法,則從Callbacks中提取最前的一個callback,并執行它。
對于Deferred對象,我們至少需要resolve和reject兩個方法。進行成功和失敗的調用。并且能夠進行鏈式調用。
var Deferred = function () { this.successCbs = new Callbacks(); this.errorCbs = new Callbacks(); } Deferred.prototype.then = function (successCb, errorCb) { this.successCbs.add(successCb); this.errorCbs.add(errorCb); return this; } Deferred.prototype.resolve = function () { this.successCbs.fire(); return this; } Deferred.prototype.reject = function () { this.errorCbs.fire(); return this; }
這樣簡單完成之后,我們新建一個Deferred實例,就能夠通過鏈式調用的方式進行異步操作。
var deferred = new Deferred(); function printA() { setTimeout(function () { console.log("A"); deferred.resolve(); }, 1000); return deferred; } function printB() { setTimeout(function () { console.log("B"); deferred.resolve(); }, 1000); } printA() .then(printB) .then(printA)
同樣的,我們可以封裝一個自制tiny-Deferred對象的tiny-ajax方法。
var ajax = function (options) { var xhrOptions = { type: options.type || "get", url: options.url || "/default/path", async: options.async || true }; var deferred = new Deferred(); var xhr = new XHRHttpRequest(); xhr.open(xhrOptions.type, xhrOptions.url, xhrOptions.async); xhr.onload = function (result) { deferred.resolve(result); } xhr.onerror = function () xhr.send(); return deferred; }
具體源代碼開源在Github上,歡迎pr和issuses。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91314.html
摘要:在前端這個領域里面,請求非常常見,相信每一個前端都寫過下面的代碼前提引入上面這段代碼中的和被稱為回調函數。多個請求希望有一個共同的回調響應繼續使用最初的方法,假設有多個請求,希望在全部完成后執行回調函數。異步編程延遲對象篇 在前端這個領域里面,ajax請求非常常見,相信每一個前端er都寫過下面的代碼: // 前提引入jquery $.ajax({ type: get, ...
摘要:一異步編程原理顯然,上面這種方式和銀行取號等待有些類似,只不過銀行取號我們并不知道上一個人需要多久才會完成。下面來探討下中的異步編程原理。 眾所周知,JavaScript 的執行環境是單線程的,所謂的單線程就是一次只能完成一個任務,其任務的調度方式就是排隊,這就和火車站洗手間門口的等待一樣,前面的那個人沒有搞定,你就只能站在后面排隊等著。在事件隊列中加一個延時,這樣的問題便可以得到緩解...
摘要:在服務器端,異步模式甚至是唯一的模式,因為執行環境是單線程的,如果允許同步執行所有請求,服務器性能會急劇下降,很快就會失去響應。第三是,捕捉不到他的錯誤異步編程方法回調函數這是異步編程最基本的方法。 前言 你可能知道,Javascript語言的執行環境是單線程(single thread)。所謂單線程,就是指一次只能完成一件任務。如果有多個任務,就必須排隊,前面一個任務完成,再執行后面...
摘要:為此決定自研一個富文本編輯器。例如當要轉化的對象有環存在時子節點屬性賦值了父節點的引用,為了關于函數式編程的思考作者李英杰,美團金融前端團隊成員。只有正確使用作用域,才能使用優秀的設計模式,幫助你規避副作用。 JavaScript 專題之惰性函數 JavaScript 專題系列第十五篇,講解惰性函數 需求 我們現在需要寫一個 foo 函數,這個函數返回首次調用時的 Date 對象,注意...
showImg(https://segmentfault.com/img/bVbjYU7?w=2000&h=1333); 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! JavsScript 是一門單線程的編程語言,這就意味著一個時間里只能處理一件事,也就是說 JavaScript 引擎一次只能在一個線程里處理一條語句。 雖然單線程簡化了編程代碼,因為你不必太擔心并發引出的問...
閱讀 2335·2021-11-15 11:38
閱讀 3544·2021-09-22 15:16
閱讀 1187·2021-09-10 11:11
閱讀 3156·2021-09-10 10:51
閱讀 2921·2019-08-30 15:56
閱讀 2774·2019-08-30 15:44
閱讀 3185·2019-08-28 18:28
閱讀 3525·2019-08-26 13:36