摘要:上篇文章中講到,使用的方法操作請求,會受到回調(diào)函數(shù)嵌套的問題。第一次回調(diào)第二次回調(diào)內(nèi)部實(shí)現(xiàn)上,和都是基于實(shí)現(xiàn)的對于多個(gè)同時(shí)請求,共同執(zhí)行同一個(gè)回調(diào)函數(shù)這一點(diǎn)上,有一個(gè)方法,接受多個(gè)對象實(shí)例,同時(shí)執(zhí)行。
上篇文章中講到,使用jquery的ajax方法操作ajax請求,會受到回調(diào)函數(shù)嵌套的問題。當(dāng)然,jquery團(tuán)隊(duì)也發(fā)現(xiàn)了這個(gè)問題,在2011年,也就是jquery 1.5版本之后,jQuery.Deferred對象為解決這類問題應(yīng)運(yùn)而出。之后,zapto等框架也推出相同api的deferred對象,來進(jìn)行異步操作。
在jquery 1.5 版本之后,ajax請求的內(nèi)部實(shí)現(xiàn)被重寫。$.ajax方法返回的不再是一個(gè)jqXHR對象,而是一個(gè)Deferred對象。
使用jquery 1.5版本之后的代碼,可以用下面的方法進(jìn)行一次ajax請求。
// 前提引入jquery var fetchData = function (url) { return $.ajax({ type: "get", url: url }); }
這樣一次請求的內(nèi)容就已經(jīng)完成,$.ajax返回一個(gè)$.Deferred對象,那么我們就可以使用$.Deferred對象的api進(jìn)行一些異步操作。
出于篇幅,這里只簡單進(jìn)行介紹.done,.fail,.then和$.when這三個(gè)方法。
對于每一個(gè)$.Deferred對象來說,實(shí)例有多個(gè)方法,其中done方法代表異步完成時(shí)執(zhí)行的方法,fail代表異步失敗時(shí)執(zhí)行的方法,這兩個(gè)方法同時(shí)仍舊返回一個(gè)$.Deferred對象的實(shí)例。
繼續(xù)上面的ajax操作,我們可以這樣寫成功和失敗的回調(diào):
// fetchData 接上 fetchData() //執(zhí)行函數(shù)返回一個(gè)Deferred對象實(shí)例 .done() //接受一個(gè)函數(shù),ajax請求成功調(diào)用 .fail() //接受一個(gè)函數(shù),ajax請求失敗調(diào)用 .done() //第二個(gè)成功狀態(tài)的回調(diào)方法 .fail()
同樣的對于.then方法,接受兩個(gè)函數(shù),第一個(gè)代表成功時(shí)執(zhí)行的方法,第二個(gè)代表失敗時(shí)的執(zhí)行方法。同樣的,它也返回一個(gè)deferred對象實(shí)例。意味著也能進(jìn)行連綴調(diào)用。
fetchData() .then(successFn, errorFn) //第一次回調(diào) .then(successFn, errorFn) //第二次回調(diào)
內(nèi)部實(shí)現(xiàn)上,.done 和 .fail 都是基于 .then實(shí)現(xiàn)的
fetchData() fetchData() .done(successFn) <===> .then(successFn, null) .fail(errorFn) <===> .then(null, errorFn)
對于多個(gè)ajax同時(shí)請求,共同執(zhí)行同一個(gè)回調(diào)函數(shù)這一點(diǎn)上,jquery有一個(gè)$.when方法,接受多個(gè)Deferred對象實(shí)例,同時(shí)執(zhí)行。
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 響應(yīng)為data1 // fetchData2 響應(yīng)為data2 })
完美解決了開發(fā)中的異步問題。
上面的$.ajax只是在$.deferred對象上封裝了一層ajax操作。實(shí)際上,真正的$.Deferred對象是這樣調(diào)用的:
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)
每個(gè)函數(shù)維護(hù)一個(gè)Deferred對象,在每一個(gè)具有異步操作的函數(shù)執(zhí)行成功后,指示全局deferred對象執(zhí)行下一個(gè)函數(shù),達(dá)到異步的效果。
新建完成$.Deferred實(shí)例deferred之后,調(diào)用deferred.resolve()代表成功完成響應(yīng),deferred.reject()即代表調(diào)用失敗響應(yīng)。
詳細(xì)解釋源碼請參見另一篇文章,這里我們主要寫一下這種調(diào)用方式實(shí)現(xiàn)的tiny版。
首先我們寫一個(gè)Callback對象維護(hù)我們的回調(diào)函數(shù)隊(duì)列
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對象有兩個(gè)方法,分別是add和fire,調(diào)用add則向當(dāng)前的callbacks數(shù)組內(nèi)新增一個(gè)function。fire方法,則從Callbacks中提取最前的一個(gè)callback,并執(zhí)行它。
對于Deferred對象,我們至少需要resolve和reject兩個(gè)方法。進(jìn)行成功和失敗的調(diào)用。并且能夠進(jìn)行鏈?zhǔn)秸{(diào)用。
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; }
這樣簡單完成之后,我們新建一個(gè)Deferred實(shí)例,就能夠通過鏈?zhǔn)秸{(diào)用的方式進(jìn)行異步操作。
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)
同樣的,我們可以封裝一個(gè)自制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。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/91314.html
摘要:在前端這個(gè)領(lǐng)域里面,請求非常常見,相信每一個(gè)前端都寫過下面的代碼前提引入上面這段代碼中的和被稱為回調(diào)函數(shù)。多個(gè)請求希望有一個(gè)共同的回調(diào)響應(yīng)繼續(xù)使用最初的方法,假設(shè)有多個(gè)請求,希望在全部完成后執(zhí)行回調(diào)函數(shù)。異步編程延遲對象篇 在前端這個(gè)領(lǐng)域里面,ajax請求非常常見,相信每一個(gè)前端er都寫過下面的代碼: // 前提引入jquery $.ajax({ type: get, ...
摘要:一異步編程原理顯然,上面這種方式和銀行取號等待有些類似,只不過銀行取號我們并不知道上一個(gè)人需要多久才會完成。下面來探討下中的異步編程原理。 眾所周知,JavaScript 的執(zhí)行環(huán)境是單線程的,所謂的單線程就是一次只能完成一個(gè)任務(wù),其任務(wù)的調(diào)度方式就是排隊(duì),這就和火車站洗手間門口的等待一樣,前面的那個(gè)人沒有搞定,你就只能站在后面排隊(duì)等著。在事件隊(duì)列中加一個(gè)延時(shí),這樣的問題便可以得到緩解...
摘要:在服務(wù)器端,異步模式甚至是唯一的模式,因?yàn)閳?zhí)行環(huán)境是單線程的,如果允許同步執(zhí)行所有請求,服務(wù)器性能會急劇下降,很快就會失去響應(yīng)。第三是,捕捉不到他的錯(cuò)誤異步編程方法回調(diào)函數(shù)這是異步編程最基本的方法。 前言 你可能知道,Javascript語言的執(zhí)行環(huán)境是單線程(single thread)。所謂單線程,就是指一次只能完成一件任務(wù)。如果有多個(gè)任務(wù),就必須排隊(duì),前面一個(gè)任務(wù)完成,再執(zhí)行后面...
摘要:為此決定自研一個(gè)富文本編輯器。例如當(dāng)要轉(zhuǎn)化的對象有環(huán)存在時(shí)子節(jié)點(diǎn)屬性賦值了父節(jié)點(diǎn)的引用,為了關(guān)于函數(shù)式編程的思考作者李英杰,美團(tuán)金融前端團(tuán)隊(duì)成員。只有正確使用作用域,才能使用優(yōu)秀的設(shè)計(jì)模式,幫助你規(guī)避副作用。 JavaScript 專題之惰性函數(shù) JavaScript 專題系列第十五篇,講解惰性函數(shù) 需求 我們現(xiàn)在需要寫一個(gè) foo 函數(shù),這個(gè)函數(shù)返回首次調(diào)用時(shí)的 Date 對象,注意...
showImg(https://segmentfault.com/img/bVbjYU7?w=2000&h=1333); 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! JavsScript 是一門單線程的編程語言,這就意味著一個(gè)時(shí)間里只能處理一件事,也就是說 JavaScript 引擎一次只能在一個(gè)線程里處理一條語句。 雖然單線程簡化了編程代碼,因?yàn)槟悴槐靥珦?dān)心并發(fā)引出的問...
閱讀 2347·2021-11-15 11:38
閱讀 3557·2021-09-22 15:16
閱讀 1200·2021-09-10 11:11
閱讀 3170·2021-09-10 10:51
閱讀 2949·2019-08-30 15:56
閱讀 2789·2019-08-30 15:44
閱讀 3194·2019-08-28 18:28
閱讀 3533·2019-08-26 13:36