摘要:和和都有和,但是略有不同。實際上返回的是一個對象。和添加的回調(diào),添加的回調(diào)。所以在調(diào)用成功的情況下執(zhí)行添加的回調(diào),調(diào)用失敗時執(zhí)行添加的回調(diào)。,產(chǎn)生對象并,產(chǎn)生對象并,然后繼續(xù)處理,的語法糖,和的差不多但不同。
Deferred 和 Promise
ES6 和 jQuery 都有 Deffered 和 Promise,但是略有不同。不過它們的作用可以簡單的用兩句話來描述
Deffered 觸發(fā) resolve 或 reject
Promise 中申明 resolve 或 reject 后應該做什么(回調(diào))
在 jQuery 中
var deferred = $.Deferred(); var promise = deferred.promise();
在 ES6 中
var deferred = Promise.defer(); var promise= defered.promise;
jQuery 的 Deferred/PromiseMDN 宣布 Deferred 在 Gecko 30 中被申明為過期,不應該再使用,而應該用 new Promise() 來代替。關于 new Promise() 將在后面說明。
jQuery 中最常用的 Promise 對象是 $.ajax() 返回的,最常用的方法不是 then,而是 done、fail 和 always。除了 $.ajax() 外,jQuery 也提供了 $.get()、$.post() 和 $.getJSON() 等簡化 Ajax 調(diào)用,它們返回的和 $.ajax() 的返回值一樣,是個 Promise 對象。
done()、fail() 和 always()實際上 $.ajax() 返回的是一個 jqXHR 對象。但 jqXHR 實現(xiàn)了 jQuery 的 Promise 接口,所以也是一個 Promise 對象。
done() 添加 deferred.resolve() 的回調(diào),fail() 添加 deferred.reject() 的回調(diào)。所以在 Ajax 調(diào)用成功的情況下執(zhí)行 done() 添加的回調(diào),調(diào)用失敗時執(zhí)行 fail() 添加的回調(diào)。但不管成功與否,都會執(zhí)行 always() 添加的回調(diào)。
這里 done()、fail() 和 always() 都是以類似事件的方式添加回調(diào),也就意味著,不管執(zhí)行多次次 done()、fail() 或 always(),它們添加的若干回調(diào)都會在符合的條件下依次執(zhí)行。
一般情況下會這樣執(zhí)行 Ajax
// 禁用按鈕以避免重復提交 $("#theButton").prop({ disabled: true }); // 調(diào)用 Ajax 提交數(shù)據(jù),假設返回的是 JSON 數(shù)據(jù) var jqxhr = $.ajax("do/example", { type: "post", dataType: "json", data: getFormData() }); jqxhr.done(function(jsonObject) { // Ajax 調(diào)用成功 console.log("success with data", jsonObject); }).fail(function() { // Ajax 調(diào)用失敗 console.log("failed") }).always(function() { // 不管成功與否,都會執(zhí)行,取消按鈕的禁用狀態(tài) $("#theButton").prop({ disabled: false }); });
上面是最普通最常用的用法,但是在一個項目中總是這么寫 Ajax,有點累,稍微約定一下再封裝一下就使用起來就會便捷得多。首先,假設我們定義返回的 JSON 是這樣的格式:
{ "code": "int, 0 表示成功,其它值表示出錯", "message": "string, 附加的消息,可選", "data": "object,附加的數(shù)據(jù),可選 }
然后為項目公共類 app 定義一個 ajax 方法
app.ajax = function(button, url, data) { if (button) { button.prop("disabled", true); } return $.ajax(url, { type: "post", dataType: "json", data: data }).done(function(json) [ if (json.code !== 0) { showError(json.message || "操作發(fā)生錯誤"); } }).fail(function() { showError("服務器錯誤,請稍后再試"); }).always(function() { if (button) { button.prop("disabled", false); } }); }; // 調(diào)用 app.ajax("do/example", getFormData()).done(function(json) { if (json.code === 0) { // 只需要處理正確的情況啦 } });
不過還是有點不爽,如果不需要判斷 json.code === 0 就更好了。這個……可以自己用一個 Deferred 來處理:
app.ajax = function(button, url, data) { if (button) { button.prop("disabled", true); } var deferred = $.Deferred(); $.ajax(url, { type: "post", dataType: "json", data: data }).done(function(json) [ if (json.code !== 0) { showError(json.message || "操作發(fā)生錯誤"); deferred.reject(); } else { deferred.resolve(json); } }).fail(function() { showError("服務器錯誤,請稍后再試"); deferred.reject(); }).always(function() { if (button) { button.prop("disabled", false); } }); return deferred.promise(); }; // 調(diào)用 app.ajax("do/example", getFormData()).done(function(json) { // json.code === 0 總是成立 // 正常處理 json.data 就好 });
注意,這里已經(jīng)不是直接返回 $.ajax() 的結果 jqXHR 對象了,返回的是新建 Deferred 對象的 promise 對象。
復習了 Ajax,現(xiàn)在需要切入正題,找到 jQuery Promise 和 ES6 Promise 接近的地方——then()。
jQuery deferred.then()在 jQuery 1.8 以前(不含 1.8,比如 jQuery 1.7.2),deferred.then() 就是一個把 done() 和 fail() 放在一起的語法糖。jQuery 在 1.8 版本的時候修改了 deferred.then() 的行為,使 then() 的行為與 Promise 的 then() 相似。從 jQuery 的文檔可以看到 1.8 版本的變化——干掉了 callback,換成了 filter:
// version added: 1.5, removed: 1.8 deferred.then( doneCallbacks, failCallbacks ) // version added: 1.7, removed: 1.8 deferred.then( doneCallbacks, failCallbacks [, progressCallbacks ] ) // version added: 1.8 deferred.then( doneFilter [, failFilter ] [, progressFilter ] )
可以簡單的把 callback 當作一個事件處理,值用于 callback 之后一般不會改變;而 filter 不同,一個值傳入 filter 再從 filter 返回出來,可能已經(jīng)變了。還是舉個例子來說明
var deferred = $.Deferred(); var promise = deferred.promise(); promise.then(function(v) { console.log(`then with ${v}`); }).done(function(v) { console.log(`done with ${v}`); }); deferred.resolve("resolveData");
在 jQuery 1.7.2 中的結果
then with resolveData done with resolveData
在 jQuery 1.8.0 中的結果
then with resolveData done with undefined
從上面來看,jQuery 的 deferred.then() 語義和 ES6 Promise.then() 語義基本一致。如果把上面的 app.ajax 換成 then() 實現(xiàn)會有助于對 ES6 Promise 的理解。
app.ajax = function(button, url, data) { if (button) { button.prop("disabled", true); } return $.ajax(url, { type: "post", dataType: "json", data: data }).then(function(json) { if (json.code !== 0) { showError(json.message || "操作發(fā)生錯誤"); return $.Deferred().reject().promise(); } else { return $.Deferred().resolve(json).promise(); } }, function() { showError("服務器錯誤,請稍后再試"); deferred.reject(); }).always(function() { if (button) { button.prop("disabled", false); } }); }; // 調(diào)用方式?jīng)]變,用 done,也可以用 then app.ajax("do/example", getFormData()).done(function(json) { // json.code === 0 總是成立 // 正常處理 json.data 就好 });從 jQuery Promise 到 ES6 Promise
上面的代碼太長,提煉一下關鍵部分(示意,不能運行)
var promise = $.ajax(); promise.then(function(data) { // resolve return data.code ? new Promise().reject() : new Promise().resolve(data); // 如果沒有錯,就返回一個新的 promise,并使用 data 來 resolve, // 也可以直接返回 data, // 這樣后面 then 的 resolve 部分才能收到數(shù)據(jù) }, function() { // rejected }); // 調(diào)用階段 promise.then(function(data) { // 處理 data });
也許你沒注意到,其實上面的代碼基本上就是 ES6 的 Promise 了。下面正式用 ES6 Promise 改寫上面的示意代碼
var promise = new Promise(function(resolve, reject) { $.ajax().then(resolve, reject); // 上面這句沒看懂?那換成這樣你一定會懂 // $.ajax().then(function(data) { // resolve(data); // }, function() { // reject(); // }); }).then(function(data) { return data.code ? Promise.reject() : Promise.resolve(data); // 這里 Promise.resolve(data) 同樣可以直接替換為 data }); // 調(diào)用沒變 promise.then(function(data) { // 處理 data });
怎么樣,差別不大吧。不知不覺就會 ES6 Promise 了!
ES6 的 Promise上面已經(jīng)把 ES6 的 Promise 帶出來了,現(xiàn)在只需要把常用方法列出來作為參考即可
注意,小寫的 promise 表示 Promise 對象
new Promise(executor),產(chǎn)生一個新的 Promise 對象
> `executor(resolve, reject)` > `executor`、`resolve` 和 `reject` 均為函數(shù),在 `executor` 中,正確處理調(diào)用 `resolve()` 返回數(shù)據(jù),異常處理直接 `throw new Error(...)` 或調(diào) `reject()` 返回數(shù)據(jù)。
Promise.resolve(data),產(chǎn)生 Promise 對象并 resolve
Promise.reject(),產(chǎn)生 Promise 對象并 reject
promise.then(onResolve, onReject),然后……繼續(xù)處理
promise.catch(onReject),project.then(null, onReject) 的語法糖,和 jQuery 的 promise.fail() 差不多(但不同)。
參考ECMAScript 2015 Language Specification - ECMA-262 6th Edition
Deferred - Mozilla | MDN
Promise - Mozilla | MDN
Deferred Object | jQuery Documentation
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/85953.html
摘要:實現(xiàn)是中的一種異步編程實現(xiàn)方式,中異步編程主要是指瀏覽器事件處理,等,通過傳入回調(diào)函數(shù)來實現(xiàn)控制反轉。對象符合編程規(guī)范,目的是為異步編程提供統(tǒng)一接口,它最大的優(yōu)點就是避免了回調(diào)金字塔。 promise實現(xiàn) Promise是Javascript中的一種異步編程實現(xiàn)方式,js中異步編程主要是指瀏覽器DOM事件處理,setTimeout/setInterval,ajax等,通過傳入回調(diào)函數(shù)來...
摘要:回調(diào)隊列對象,用于構建易于操作的回調(diào)函數(shù)集合,在操作完成后進行執(zhí)行。對象對象,用于管理回調(diào)函數(shù)的多用途列表。如果傳入一個延遲對象,則返回該對象的對象,可以繼續(xù)綁定其余回調(diào),在執(zhí)行結束狀態(tài)之后也同時調(diào)用其回調(diào)函數(shù)。 在工作中我們可能會把jQuery選擇做自己項目的基礎庫,因為其提供了簡便的DOM選擇器以及封裝了很多實用的方法,比如$.ajax(),它使得我們不用操作xhr和xdr對象,直...
摘要:單線程就意味著,所有任務需要排隊,前一個任務結束,才會執(zhí)行后一個任務。這決定了它只能是單線程,否則會帶來很復雜的同步問題。小結本身是單線程的,并沒有異步的特性。當異步函數(shù)執(zhí)行時,回調(diào)函數(shù)會被壓入這個隊列。 走在前端的大道上 本篇將自己讀過的相關 js異步 的文章中,對自己有啟發(fā)的章節(jié)片段總結在這(會對原文進行刪改),會不斷豐富提煉總結更新。 概念 JS 是單線程的語言。 單線程就意味著...
摘要:結果證明,對于以上瀏覽器,在生產(chǎn)環(huán)境使用是可行的。后面可以跟對象,表示等待才會繼續(xù)向下執(zhí)行,如果被或拋出異常則會被外面的捕獲。,,都是現(xiàn)在和未來解決異步的標準做法,可以完美搭配使用。這也是使用標準一大好處。只允許外部傳入成功或失敗后的回調(diào)。 showImg(https://cloud.githubusercontent.com/assets/948896/10188666/bc9a53...
摘要:回調(diào)函數(shù)這是最原始的一種異步解決方法。從的對象演化而來對象是提出的一種對異步編程的解決方案,但它不是新的語法,而是一種新的寫法,允許將回調(diào)函數(shù)的嵌套改成鏈式調(diào)用。 一、前言 異步編程對JavaScript來說非常重要,因為JavaScript的語言環(huán)境是單線程的,如果沒有異步編程將變得非??膳?,估計根本無法使用。這篇文章就來總結一下從最原始的回調(diào)函數(shù)到現(xiàn)在的ES6、ES7的新方法。 文...
閱讀 2229·2021-11-22 13:54
閱讀 3386·2019-08-29 12:25
閱讀 3450·2019-08-28 18:29
閱讀 3595·2019-08-26 13:40
閱讀 3285·2019-08-26 13:32
閱讀 972·2019-08-26 11:44
閱讀 2242·2019-08-23 17:04
閱讀 2984·2019-08-23 17:02