摘要:一般會(huì)這樣去寫要在第一個(gè)請(qǐng)求成功后才可以執(zhí)行下一步這樣的寫法的原理是,當(dāng)執(zhí)行一些異步操作時(shí),我們需要知道操作是否已經(jīng)完成,所有當(dāng)執(zhí)行完成的時(shí)候會(huì)返回一個(gè)回調(diào)函數(shù),表示操作已經(jīng)完成。
前言
開篇首先設(shè)想一個(gè)日常開發(fā)常常會(huì)遇到的需求:在多個(gè)接口異步請(qǐng)求數(shù)據(jù),然后利用這些數(shù)據(jù)來(lái)進(jìn)行一系列的操作。一般會(huì)這樣去寫:
$.ajax({ url: "......", success: function (data) { $.ajax({ // 要在第一個(gè)請(qǐng)求成功后才可以執(zhí)行下一步 url: "......", success: function (data) { // ...... } }); } });
這樣的寫法的原理是,當(dāng)執(zhí)行一些異步操作時(shí),我們需要知道操作是否已經(jīng)完成,所有當(dāng)執(zhí)行完成的時(shí)候會(huì)返回一個(gè)回調(diào)函數(shù),表示操作已經(jīng)完成。
使用回調(diào)函數(shù)的形式理解起來(lái)并不困難,但是實(shí)際的應(yīng)用當(dāng)中會(huì)有以下的缺點(diǎn):
在需要多個(gè)操作的時(shí)候,會(huì)導(dǎo)致多個(gè)回調(diào)函數(shù)嵌套,導(dǎo)致代碼不夠直觀,就是常說(shuō)的 Callback Hell。
如果幾個(gè)異步操作之間并沒有前后順序之分(例如不需要前一個(gè)請(qǐng)求的結(jié)果作為后一個(gè)請(qǐng)求的參數(shù))時(shí),同樣需要等待上一個(gè)操作完成再實(shí)行下一個(gè)操作。
為了解決上述的問(wèn)題,Promise 對(duì)象應(yīng)運(yùn)而生,在 EMCAScript 2015 當(dāng)中已經(jīng)成為標(biāo)準(zhǔn)。
什么是 Promise一個(gè) Promise 對(duì)象可以理解為一次將要執(zhí)行的操作(常常被用于異步操作),使用了 Promise 對(duì)象之后可以用一種鏈?zhǔn)秸{(diào)用的方式來(lái)組織代碼,讓代碼更加直觀。而且由于 Promise.all 這樣的方法存在,可以讓同時(shí)執(zhí)行多個(gè)操作變得簡(jiǎn)單。接下來(lái)就來(lái)簡(jiǎn)單介紹 Promise 對(duì)象。
resolve 和 reject首先來(lái)看一段使用了 Promise 對(duì)象的代碼。
function helloWorld (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello World!"); } else { reject("Good bye!"); } }); } helloWorld(true).then(function (message) { alert(message); }, function (error) { alert(error); });
jsFiddle(請(qǐng)用現(xiàn)代瀏覽器打開)
上面的代碼實(shí)現(xiàn)的功能非常簡(jiǎn)單,helloWord 函數(shù)接受一個(gè)參數(shù),如果為 true 就打印 "Hello World!",如果為 false 就打印錯(cuò)誤的信息。helloWord 函數(shù)返回的是一個(gè) Promise 對(duì)象。
在 Promise 對(duì)象當(dāng)中有兩個(gè)重要方法————resolve 和 reject。
resolve 方法可以使 Promise 對(duì)象的狀態(tài)改變成成功,同時(shí)傳遞一個(gè)參數(shù)用于后續(xù)成功后的操作,在這個(gè)例子當(dāng)中就是 Hello World! 字符串。
reject 方法則是將 Promise 對(duì)象的狀態(tài)改變?yōu)槭。瑫r(shí)將錯(cuò)誤的信息傳遞到后續(xù)錯(cuò)誤處理的操作。
Promise 的三種狀態(tài)上面提到了 resolve 和 reject 可以改變 Promise 對(duì)象的狀態(tài),那么它究竟有哪些狀態(tài)呢?
Promise 對(duì)象有三種狀態(tài):
Fulfilled 可以理解為成功的狀態(tài)
Rejected 可以理解為失敗的狀態(tài)
Pending 既不是 Fulfilld 也不是 Rejected 的狀態(tài),可以理解為 Promise 對(duì)象實(shí)例創(chuàng)建時(shí)候的初始狀態(tài)
helloWorld 的例子中的 then 方法就是根據(jù) Promise 對(duì)象的狀態(tài)來(lái)確定執(zhí)行的操作,resolve 時(shí)執(zhí)行第一個(gè)函數(shù)(onFulfilled),reject 時(shí)執(zhí)行第二個(gè)函數(shù)(onRejected)。
then 和 catch thenhelloWorld 的例子當(dāng)中利用了 then(onFulfilld, onRejected) 方法來(lái)執(zhí)行一個(gè)任務(wù)打印 "Hello World!",在多個(gè)任務(wù)的情況下 then 方法同樣可以用一個(gè)清晰的方式完成。
function printHello (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello"); } else { reject("Good bye!"); } }); } function printWorld () { alert("World"); } function printExclamation () { alert("!"); } printHello(true) .then(function(message){ alert(message); }) .then(printWorld) .then(printExclamation);
jsFiddle
上述例子通過(guò)鏈?zhǔn)秸{(diào)用的方式,按順序打印出了相應(yīng)的內(nèi)容。then 可以使用鏈?zhǔn)秸{(diào)用的寫法原因在于,每一次執(zhí)行該方法時(shí)總是會(huì)返回一個(gè) Promise 對(duì)象。另外,在 then onFulfilled 的函數(shù)當(dāng)中的返回值,可以作為后續(xù)操作的參數(shù),因此上面的例子也可以寫成:
printHello(true).then(function (message) { return message; }).then(function (message) { return message + " World"; }).then(function (message) { return message + "!"; }).then(function (message) { alert(message); });
jsFiddle
同樣可以打印出正確的內(nèi)容。
catchcatch 方法是 then(onFulfilled, onRejected) 方法當(dāng)中 onRejected 函數(shù)的一個(gè)簡(jiǎn)單的寫法,也就是說(shuō)可以寫成 then(fn).catch(fn),相當(dāng)于 then(fn).then(null, fn)。使用 catch 的寫法比一般的寫法更加清晰明確。
Promise.all 和 Promise.racePromise.all 可以接收一個(gè)元素為 Promise 對(duì)象的數(shù)組作為參數(shù),當(dāng)這個(gè)數(shù)組里面所有的 Promise 對(duì)象都變?yōu)?resolve 時(shí),該方法才會(huì)返回。
var p1 = new Promise(function (resolve) { setTimeout(function () { resolve("Hello"); }, 3000); }); var p2 = new Promise(function (resolve) { setTimeout(function () { resolve("World"); }, 1000); }); Promise.all([p1, p2]).then(function (result) { console.log(result); // ["Hello", "World"] });
上面的例子模擬了傳輸兩個(gè)數(shù)據(jù)需要不同的時(shí)長(zhǎng),雖然 p2 的速度比 p1 要快,但是 Promise.all 方法會(huì)按照數(shù)組里面的順序?qū)⒔Y(jié)果返回。
日常開發(fā)中經(jīng)常會(huì)遇到這樣的需求,在不同的接口請(qǐng)求數(shù)據(jù)然后拼合成自己所需的數(shù)據(jù),通常這些接口之間沒有關(guān)聯(lián)(例如不需要前一個(gè)接口的數(shù)據(jù)作為后一個(gè)接口的參數(shù)),這個(gè)時(shí)候 Promise.all 方法就可以派上用場(chǎng)了。
還有一個(gè)和 Promise.all 相類似的方法 Promise.race,它同樣接收一個(gè)數(shù)組,不同的是只要該數(shù)組中的 Promise 對(duì)象的狀態(tài)發(fā)生變化(無(wú)論是 resolve 還是 reject)該方法都會(huì)返回。
兼容性最后是關(guān)于 Promise 對(duì)象的兼容性問(wèn)題。
在瀏覽器端,一些主流的瀏覽器都已經(jīng)可以使用 Promise 對(duì)象進(jìn)行開發(fā),在 Node.js 配合 babel 也可以很方便地使用。
如果要兼容舊的瀏覽器,建議可以尋找一些第三方的解決方案,例如 jQuery 的 $.Deferred。
感謝你的閱讀,有不足之處請(qǐng)為我指出。
參考
JavaScript Promise迷你書(中文版)
本文同步于我的個(gè)人博客 http://blog.acwong.org/2015/06/22/es6-promise/
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/85753.html
摘要:回調(diào)函數(shù)這是異步編程最基本的方法。對(duì)象對(duì)象是工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口。誕生后,出現(xiàn)了函數(shù),它將異步編程帶入了一個(gè)全新的階段。 更多詳情點(diǎn)擊http://blog.zhangbing.club/Ja... Javascript 語(yǔ)言的執(zhí)行環(huán)境是單線程的,如果沒有異步編程,根本沒法用,非卡死不可。 為了解決這個(gè)問(wèn)題,Javascript語(yǔ)言將任務(wù)的執(zhí)行模式分成兩種...
摘要:其實(shí)我們?cè)谕搅鞒讨胁耪f(shuō)返回,異步?jīng)]有返回這個(gè)概念或者說(shuō)異步返回是沒有意義的,異步對(duì)應(yīng)的是回調(diào),也就是說(shuō),對(duì)于一個(gè)異步函數(shù),我們應(yīng)該傳入一個(gè)回調(diào)函數(shù)來(lái)接收結(jié)果。 原文鏈接:https://www.xksblog.top/talk-... 見到wx.request的第一眼,就讓我想起了$.ajax這東西,使用起來(lái)確實(shí)有很多不方便,不能忍,幸好小程序是支持ES6語(yǔ)法的,所以可以使用pro...
摘要:異步問(wèn)題回調(diào)地獄首先,我們來(lái)看下異步編程中最常見的一種問(wèn)題,便是回調(diào)地獄。同時(shí)使用也是異步編程最基礎(chǔ)和核心的一種解決思路。基于,目前也被廣泛運(yùn)用,其是異步編程的一種解決方案,比傳統(tǒng)的回調(diào)函數(shù)解決方案更合理和強(qiáng)大。 關(guān)于 微信公眾號(hào):前端呼啦圈(Love-FED) 我的博客:勞卜的博客 知乎專欄:前端呼啦圈 前言 在實(shí)際編碼中,我們經(jīng)常會(huì)遇到Javascript代碼異步執(zhí)行的場(chǎng)景...
摘要:異步編程是每個(gè)使用編程的人都會(huì)遇到的問(wèn)題,無(wú)論是前端的請(qǐng)求,或是的各種異步。本文就來(lái)總結(jié)一下常見的四種處理異步編程的方法。利用一種鏈?zhǔn)秸{(diào)用的方法來(lái)組織異步代碼,可以將原來(lái)以回調(diào)函數(shù)形式調(diào)用的代碼改為鏈?zhǔn)秸{(diào)用。 異步編程是每個(gè)使用 JavaScript 編程的人都會(huì)遇到的問(wèn)題,無(wú)論是前端的 ajax 請(qǐng)求,或是 node 的各種異步 API。本文就來(lái)總結(jié)一下常見的四種處理異步編程的方法。...
摘要:已成功,內(nèi)部執(zhí)行了方法,實(shí)例處于狀態(tài),狀態(tài)不可改變了。實(shí)際上是函數(shù)的一種簡(jiǎn)寫形式,當(dāng)執(zhí)行后,可以被的回調(diào)函數(shù)接收處理。該語(yǔ)句并未執(zhí)行若內(nèi)部發(fā)生錯(cuò)誤,會(huì)被自動(dòng)的執(zhí)行。靜態(tài)函數(shù)返回一個(gè)成功的對(duì)象,靜態(tài)函數(shù)返回一個(gè)拒絕狀態(tài)的對(duì)象。 視頻講解 ES6的 Promise 是個(gè)啥哩?,是個(gè)承諾。為了解決 js 回調(diào)地獄。Promise 給我的體會(huì)是: 開始云里霧里,然后越用越好用。今天才明白承諾是...
閱讀 2862·2021-10-21 09:38
閱讀 2762·2021-10-11 10:59
閱讀 3048·2021-09-27 13:36
閱讀 1668·2021-08-23 09:43
閱讀 802·2019-08-29 14:14
閱讀 3040·2019-08-29 12:13
閱讀 3210·2019-08-29 12:13
閱讀 318·2019-08-26 12:24