優(yōu)雅的異步編程 Promise詳解

Promise是什么?

? ? Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案--回調(diào)函數(shù)和事件--更加合理和強(qiáng)大。最早是在社區(qū)提出和實(shí)現(xiàn),ES6將其寫進(jìn)了語言標(biāo)準(zhǔn),統(tǒng)一了語法,原生提供了Promise對(duì)象。

? ? 好吧,那Promise到底是什么?嗯。。。。貌似可以提升逼格¥0#¥@

? ? 還是少一點(diǎn)套路直接上例子比較好理解。在敞開心扉之前,先請(qǐng)客官大人記住Promise的2大特性,①Promise的對(duì)象狀態(tài)不受外界影響。②一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果。(試想你的代碼中有這么個(gè)對(duì)你忠貞的姑娘,484灰常激動(dòng)。)當(dāng)然,Promise也有一些小缺憾,后文會(huì)提到。

? ? 場景1:

? ? ? ? $.ajax({
? ? ? ? ? ? ****
? ? ? ? ? ? success:dosomething(data){}
? ? ? ? })
這是個(gè)最簡單的AJAX異步獲取數(shù)據(jù)的場景,一切都顯得那么和諧完美無瑕,簡直666,
好了,老板說我們的業(yè)務(wù)變得復(fù)雜了?

? ? 場景2:

? ? ? ?$.ajax({
? ? ? ? ? ?****
? ? ? ? ? ?success:fn(data){
? ? ? ? ? ? ? ?$ajax({
? ? ? ? ? ? ? ?***
? ? ? ? ? ? ? ?success:dosomethis(data){
? ? ? ? ? ? ? ? ? ?...
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?})
? ? ? ? ? ?}
? ? ? ?)}

這個(gè)場景描述描述的是一個(gè)AJAX請(qǐng)求依賴于另一個(gè)AJAX請(qǐng)求成功后獲得的返回值,我們寫出了兩層嵌套的AJAX連環(huán)炮,你似乎已經(jīng)能看到你的未來了,隨著我們的業(yè)務(wù)變的越來越復(fù)雜,你的代碼可讀性會(huì)變的越來越差,你的連環(huán)炮越打越長,到后面你自己也找不到中間到底哪里會(huì)出錯(cuò),會(huì)出什么錯(cuò)。這顯然不夠優(yōu)雅~

場景2會(huì)輕松形成一個(gè)叫回調(diào)地獄的場景,可以讓你的代碼維護(hù)者花上一整天來弄懂你的這一些列連環(huán)炮到底是做什么的。這似乎是個(gè)報(bào)仇的好辦法。好了,這并不好,作為一名優(yōu)雅的不行的前端開發(fā)工程師,是時(shí)候來一波無形裝逼了。

Promise基本用法

? ? var promise = new Promise(function(resolve,reject){
? ? ? ? // ... some code if(/* 異步操作成功 */){
? ? ? ? ? ? resolve(value);
? ? ? ? }else{
? ? ? ? ? ? reject(error);}
? ? ? ? });

Prominse構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolvereject。他們是兩個(gè)函數(shù),由JavaScript引擎提供,不用自己部署。(通俗點(diǎn)講就是。一個(gè)帶了兩個(gè)奇怪的函數(shù)作為參數(shù)的函數(shù)把你的異步代碼包裹起來了作為參數(shù)給了Promise構(gòu)造器造了一個(gè)Promise實(shí)例。優(yōu)雅么,酸爽么,%……%¥)

那函數(shù)里面是什么鬼,回顧剛剛讓你特別記住的兩點(diǎn)的。就是每個(gè)Promise對(duì)象都有一個(gè)保存保存狀態(tài)的功能,當(dāng)Promise實(shí)例被創(chuàng)建出來的時(shí)候,她有了第一個(gè)狀態(tài)Pending,然后被你包裹的那段異步代碼開始執(zhí)行,&……¥¥#*,如果一切ok,異步操作成功了,執(zhí)行埋伏已久的resolve函數(shù),并且把需要處理的返回值作為參數(shù)傳遞出去,Promise對(duì)象的狀態(tài)從Pending置成Resolved(又稱Fulfilled),要是其中發(fā)生了什么亂七八糟牛鬼蛇神的事情導(dǎo)致的異步操作失敗了,執(zhí)行reject函數(shù)并將錯(cuò)誤信息傳遞出去,Promise對(duì)象的狀態(tài)就會(huì)從Pending置成Rejected,你還需要記住剛剛的第二點(diǎn),這個(gè)狀態(tài)的改變不可逆且不可重復(fù)改變。這就是Promise承若的名字由來吧,多么美麗美好,仿佛看見十八歲的妹子在對(duì)你Promise Promise P...。

Promise實(shí)例生成以后,可以用then的方法指定Resolved狀態(tài)和Reject狀態(tài)的回調(diào)函數(shù)。先看寫法

? ? promise.then(function(value){
? ? ? ? // success
? ? },function(error){
? ? ? ?// failure
? ? });

then方法可以接收兩個(gè)回調(diào)函數(shù)作為參數(shù),第一個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變成Resolved時(shí)的回調(diào),第二個(gè)則是Promise對(duì)象的狀態(tài)變?yōu)?i>Rejected時(shí)調(diào)用。第二個(gè)參數(shù)是可選的,這兩個(gè)函數(shù)都自動(dòng)接收Promise對(duì)象傳出的值作為參數(shù)。

說了這么多,我們來看看如何改下我們之前的場景2

首先我們把異步操作都交給Promise去實(shí)例一個(gè)Promise對(duì)象,并且封裝到一個(gè)方法作為返回值以供鏈?zhǔn)秸{(diào)用。

function doFir (){
? ? return new Promise((resolve,reject)=>{
? ? ? ? $.ajax({
? ? ? ? ? ? ****
? ? ? ? ? ? success:resolve(value)? //成功后改變Promise的狀態(tài)并且將value交給resolve傳遞出去
? ? ? ? ? ? error:reject(err)? //失敗后 將Promise狀態(tài)Rejected并且將err交給reject傳遞出去
? ? ? ? })
? ? }) ?//整個(gè)Promise實(shí)例作為返回值返回出去
}

function doSec(value){
? ? return new Promise((resolve,reject)=>{
? ? ? ? $.ajax({
? ? ? ? ? ? ****
? ? ? ? ? ? success:resolve(value)? //成功后改變Promise的狀態(tài)并且將value交給resolve傳遞出去
? ? ? ? ? ? error:reject(err)? //失敗后 將Promise狀態(tài)Rejected并且將err交給reject傳遞出去
? ? ? ? })
? ? })? //整個(gè)Promise實(shí)例作為返回值返回出去
}

function doThi(value){
? ? return new Promise((resolve,reject)=>{
? ? ? ? $.ajax({
? ? ? ? ? ? ****
? ? ? ? ? ? success:resolve(value)? //成功后改變Promise的狀態(tài)并且將value交給resolve傳遞出去
? ? ? ? ? ? error:reject(err)? //失敗后 將Promise狀態(tài)Rejected并且將err交給reject傳遞出去
? ? ? ? })
? ? })? //整個(gè)Promise實(shí)例作為返回值返回出去
}

為了體現(xiàn)Promise的優(yōu)雅,多加了一個(gè)異步操作,注意現(xiàn)在三個(gè)任務(wù)函數(shù)的關(guān)系是并列的,他們共享同一個(gè)作用域,在作用域鏈中的位置也是同級(jí)的,作用域鏈不理解的同學(xué)跳過沒關(guān)系。然后開始展現(xiàn)Promise的優(yōu)雅。bi~~~u~~

doFir().then((value) => {doSec(value)})
? ? ? ? ? ?.then((value) => {doThi(value)})

QAQ!~~~好吧我們稍微拆解一下說明其中的那些優(yōu)雅
doFir()
? ? ? ? ? .then((value) => {doSec(value)})//這里then省略了第二個(gè)參數(shù),也就是Promise為Rejected時(shí)候的回調(diào),第一個(gè)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //回調(diào)函數(shù)會(huì)接收到success:resolve(value)傳遞出來的value參數(shù),開始執(zhí)行? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //doSec()
? ? ? ? ? .then((value) => {doThi(value)})//因?yàn)閐oSec()返回的是一個(gè)新的Promise對(duì)象,一樣的你可以接著then

至此,一個(gè)嵌套的多層級(jí)的異步代碼塊通過使用Promise扁平化了,閱讀者和編程者都能快速清晰的知道這一串鏈?zhǔn)秸{(diào)用到底要做什么。

好吧 優(yōu)雅的和大家說88~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容