趣味探索promise的秘密

網(wǎng)上也有很多關于promise的講解,但感覺都停留在理論層面,對于讀者來說,看了一遍,似乎已經(jīng)全部明白了,但真要用起來,發(fā)現(xiàn)還是無從下手。因此,本文旨在用人話為小伙伴們解釋一下promise到底真正怎么用。
最近的項目里包含了大量的表單交互,必然免不了各種異步請求,promise使用相當頻繁。我想,是時候來與小伙伴們分享一下我遇到的各種promise的坑了。

promise干嘛用的?----一般用于異步操作。
為什么能用來異步操作?----因為能等一個函數(shù)執(zhí)行完之后執(zhí)行下一個函數(shù)操作。
懂了嗎?----懂了
那好,用一個我看看----額,那個。。到底怎么寫來著。。
你不是都懂了嗎?----是啊,道理我都懂啊,但為什么就是不會用呢。。

哈哈,這就是我最初使用promise的深刻感受,明明那些概念都懂,語法也并不復雜,可就是實際用的時候用不出來。如果你也有這種感受,那么,恭喜你,來對地方了,跟著我繼續(xù)探索promise的秘密吧!

promise和then的配套使用

我們來想象這么一個生活情境:

開學了,幼兒園里的小朋友們排排坐,老師說:小朋友們,讓我們來介紹自己的名字好不好呀,那么,從第一排的小紅開始,依次往下介紹,好,我們開始吧!
小紅站起來說,大家好,我叫小紅,
接著小強站起來說,大家好,我叫小強

。
接著,輪到小明了,小明有個缺點,就是一緊張就口吃,只聽他紅著臉,站起來說:大。。大。。大。。大。。家。。好。。好。。
還沒說完呢,后面的急性子小剛就站了起來,說:大家好,我叫小剛
說完,小剛后面的同學就接著站了起來,繼續(xù)介紹自己。
最后,最后一排的同學也介紹完自己,坐下去了。此時,到家聽到小明的聲音:我叫。。叫。。叫。。。叫。。叫。。
此時,老師也不耐煩了,說:行了,小明,坐下吧
可憐的小明,就這樣,連一個自我介紹都沒有完成。。。

好了,親,記住上面的故事了嗎?我們開始學習promise。本來大家都好好的,按順序自我介紹,挺好。但畢竟人生不如意十之八九,誰能想到小明有些口吃呢,所以小剛就搶著自我介紹了,你可能想說,這都怪小剛,可人家小剛還委屈呢,老師說的,按照座位來的,既然小明已經(jīng)開始自我介紹了,那我就開始嘛,誰知道他這么慢呢。
對,小明就是這個異步操作,異步請求和接受服務器相應都是需要時間的,但是人家正常的js程序不管這些,一條語句執(zhí)行了,下一條語句就會接著執(zhí)行,不會去管上一條語句又沒有完成,程序員你也沒說要必須等上一條語句執(zhí)行完才能執(zhí)行下一條啊。
這樣的問題在哪里呢,問題在最后,老師統(tǒng)計班上同學姓名的時候,會直接把小明漏掉,因為統(tǒng)計的時候,他都沒有自我介紹完?。∫簿褪钦f,你后面的語句需要用到前面異步的返回值的時候,就會接收不到!
故事還沒完呢,接下來聽第二段:

第二年,小明班上換了一個班主任,這回小明學聰明了,提前就跟老師說明了他的情況,于是老師想了個辦法。
老師說,同學們,我們今年的自我介紹,換一種方式,每一位同學在自我介紹之前,必須要先說出前一位同學的名字,才能進行自我介紹,這樣小剛就算再性急,也必須要等小明自我介紹完了才能開始自我介紹。
多么聰明的老師啊,這樣,任何同學,都能做完一個完整的自我介紹了!

老師的做法,就是promise。后一個同學必須要等錢一個同學說完,因為他需要前一個同學的名字。來看promise的語法:

new Promise((resolve,reject)=>{
// dosomething(異步操作);
    resolve(value)
})

把老師的做法翻譯成js語句就是這樣:

var m=new Promise((resolve,reject)=>{
    console.log('小明開始自我介紹')
    setTimeout(()=>{//用定時器模擬的異步操作(小明口吃)
        var name='小明'
        resolve(name)
    },3000)
})
m.then(model=>{
    var preName=model
    var name='小剛'
    console.log(preName)
    console.log(name)
})

執(zhí)行結果如下:

QQ截圖20170208152427.jpg

你會發(fā)現(xiàn),不光是小明在等待了3秒后才打印出來,小剛也一樣是等待了3秒后才打印出來,這充分說明了promise的特點,同時我都不用再解釋,相信then的用法相信小伙伴們也能很輕易的學會了!

Promise.all的應用場合

接下來,說說Promise.all的應用場合,同樣,上故事:

開學第二天,老師需要統(tǒng)計學生們的個人信息,于是讓班長小紅給每人發(fā)了一張個人信息表,讓他們填寫,并囑咐她,一定要等所有的同學都填完了,再收上來。小紅心里偷偷的笑了,肯定老師已經(jīng)知道小華寫字特別慢了。。

天啊,這到底是怎樣一個班級,口吃的、寫字慢的。。。為老師默哀一秒鐘。。。
咳咳,說正事。其實老師的囑咐,便是Promise.all的做法,Promise.all語法如下:

Promise.all(arr)

arr是一個包含Promise對象元素的數(shù)組,可能這么說還是有點抽象,那接下來把老師的做法翻譯成js:

var xiaoming=new Promise((resolve,reject)=>{
    setTimeout(()=>{
        var info={name:'xiaoming',age:'5'}
        resolve(info)
    },2000)
})
var xiaogang=new Promise((resolve,reject)=>{
    setTimeout(()=>{
        var info={name:'xiaogang',age:'6'}
        resolve(info)
    },1000)
})
var xiaohua=new Promise((resolve,reject)=>{
    setTimeout(()=>{
        var info={name:'xiaohua',age:'7'}
        resolve(info)
    },5000)
})
var arr=[xiaoming,xiaogang,xiaohua]
Promise.all(arr).then(model=>{
    console.log(model)
})

結果如你所料,在等待了5秒后,控制臺打印出了三個人的信息:

QQ截圖20170208154348.png

Promise.all的用法也就一目了然了,它會讓多個互不影響的Promise里的語句同時執(zhí)行,等待所有的Promise語句全部執(zhí)行完,然后執(zhí)行then里的操作,返回給then的model是所有Promise里的resolve的值組成的一個數(shù)組。

promise的異常處理

同志們,接下來,嘿嘿嘿,繼續(xù)講故事:

在填寫個人信息的時候,小智的通知看到他填的年齡是8歲,于是指著他說:哈哈哈,你個智障,8歲還讀幼兒園。。。小智惱羞成怒,和同桌大打了一架,打架中途,個人信息表也被同桌給撕了。這下子,班長小紅苦惱了,老師可是說,要等每個人都寫完再把他們所有的信息表收上來,這可怎么辦啊。。。

好了,我們暫且先不要管這個班里為什么會有這么多奇葩。我們來看邏輯,本來異步請求正常執(zhí)行完,接下來就執(zhí)行then里的resolve,那現(xiàn)在如果向服務器請求失敗了,又會怎么樣呢,總不能還是執(zhí)行吧,直接看代碼:

var xiaozhi=new Promise((resolve,reject)=>{
    setTimeout(()=>{
        var info={name:'xiaozhi',age:'8'}
        var reason='打架,小智的信息表被撕了'
        if(reason){
            info=null
            reject(reason) 
        }else{
            resolve(info)
        }
        
    },5000)
})
xiaozhi.then(model=>{
    console.log(model)
},error=>{
    console.log('提交個人信息表失敗')
    console.log('原因是'+error)
})

這段代碼執(zhí)行結果如下:

Paste_Image.png

小智因為這個事情,被老師狠狠的批評了一頓,他不禁想,如果時光能夠倒流,當初沒有打這個架該多好啊。小伙伴們,你應該明白我的意思了,不打架,reason就是undefined,就會進入else里的語句,就能正常的輸出給then的model了。實際情況正是如此,你很難保證你的請求就一定能夠成功響應,如果沒有成功請求到數(shù)據(jù),你就應該攔住它,執(zhí)行請求失敗的情況的語句。
可能有的小伙伴會錯誤的理解為,失敗那不就是語句執(zhí)行錯誤嗎?這里一定要主要,這里的失敗是指異步請求的失敗,并不是js語句的執(zhí)行失敗。換句話說,這里的失敗,是你自己定義的失敗,如果你非要把請求成功定義為失敗,那也會照樣進入reject,而不會執(zhí)行resolve。

Promise.all的異常處理

Promise.all的異常處理是什么樣子呢,看代碼:

var xiaoming=new Promise((resolve,reject)=>{
    setTimeout(()=>{
        var info={name:'xiaoming',age:'5'}
        resolve(info)
    },2000)
})
var xiaogang=new Promise((resolve,reject)=>{
    setTimeout(()=>{
        var info={name:'xiaogang',age:'6'}
        resolve(info)
    },1000)
})
var xiaohua=new Promise((resolve,reject)=>{
    setTimeout(()=>{
        var info={name:'xiaohua',age:'7'}
        resolve(info)
    },5000)
})
var xiaozhi=new Promise((resolve,reject)=>{
    setTimeout(()=>{
        var info={name:'xiaozhi',age:'8'}
        var reason='打架,小智的信息表被撕了'
        if(reason){
            info=null
            reject(reason) 
        }else{
            resolve(info)
        }
    },1000)
})

var arr=[xiaoming,xiaogang,xiaohua,xiaozhi]
Promise.all(arr).then(model=>{
    console.log(model)
},error=>{
    console.log('收上來失敗')
})

執(zhí)行結果如下:

Paste_Image.png

1秒的時候,打印出“收上來失敗”這句話,就好比

小紅把除了小智的其他人的信息表全部收上來了給老師,老師一看,少了小智的,說:少了小智的,重新發(fā)下去吧,這信息表不全,收上來我也不要。

看到了吧,Promise.all就是保證所有的Promise都是成功的,只要有一個失敗,它就執(zhí)行reject,并且其他的哪怕是成功的Promise結果也都全部舍棄。這叫,一個都不能少!

怎么樣,小伙伴們,看了這篇文章,是否如同剝開了Promise身上的那層薄紗,將她看了個仔細呢(咳咳,別想歪。。。)。

如果覺得文章不錯,請在下方點贊支持我哦!

參考資料

MDN官方文檔--Promise

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容