promise的基礎(chǔ)內(nèi)容可以看MDN或者阮一峰大大的博客
我看了MDN和博客之后,對(duì)promise一知半解,很多地方都搞不明白。
所以說一定要實(shí)踐句各,技術(shù)這東西光在紙面是不行的。小程序正好在寫一個(gè)登錄邏輯晴叨,有很多異步和等待的過程,下面從實(shí)際場(chǎng)景出發(fā)來說一說promise矾屯。
看完了之后你可能會(huì)有一些新的理解兼蕊。
我用了mpvue,中間涉及到了vuex
問題和需求
我設(shè)計(jì)的登錄邏輯是:
- 查看userinfo是否有值件蚕,沒有值需要賦值
- 然后查看info更新狀態(tài)孙技,如果未更新需要向服務(wù)器發(fā)送更新請(qǐng)求
- userinfo有值且info不用更新,直接調(diào)用登錄接口
一點(diǎn)題外話
說明一下這個(gè)狀態(tài)更新排作,狀態(tài)更新接口有兩個(gè)目的:
- 注冊(cè)
- 更新用戶信息
為什么不用一個(gè)專門的接口來接收用戶第一次使用的注冊(cè)信息呢牵啦?
小程序是沒有直接接口獲取用戶的openid的,但是openid又是注冊(cè)時(shí)候一個(gè)必須的參數(shù)妄痪。
小程序唯一拿到openid發(fā)方法就是登錄的code哈雏。所以要注冊(cè)必定先拿到登錄code。
這種情況下專門搞一個(gè)注冊(cè)接口我覺得意義不大衫生,這個(gè)接口和登錄接口的區(qū)別僅僅是上傳了用戶信息裳瘪。但是你用戶信息總是需要一個(gè)接口來接收更新的吧,干脆合并在一起得了罪针。
繼續(xù)說
這個(gè)邏輯非常簡(jiǎn)單彭羹,但是我下午搞了兩個(gè)小時(shí)都沒搞完,問題出在小程序接口大量的異步調(diào)用上泪酱。
我用偽碼描述一下整個(gè)過程涉及到的異步調(diào)用
if (!userinfo) {
授權(quán)了嗎({
success(res) {
if (!授權(quán)) {
授權(quán)()
}
獲取userinfo({
success(res) {
存儲(chǔ)更新()
}
})
}
}
}
if (!updated) {
更新請(qǐng)求()
} else {
登錄()
}
// 登錄我單獨(dú)拿出來了 因?yàn)榈卿浀姆椒ê竺孀鰯r截還要用
登錄() {
登錄接口({
success() {}
}
}
看起來很好地實(shí)現(xiàn)了前面的邏輯派殷,然而實(shí)際上还最,真這么簡(jiǎn)單怎么會(huì)由回調(diào)地獄呢。
這里的問題是毡惜,userinfo和logincode都是異步的拓轻,請(qǐng)求的時(shí)候還沒有拿到值。
這里算是一個(gè)很經(jīng)典的異步處理情景虱黄,以前倒是看了不少回調(diào)地獄悦即,總是要自己遇上才會(huì)真正認(rèn)識(shí)的。
應(yīng)用promise
要處理這個(gè)問題橱乱,自然的思路就是等待回調(diào)完成辜梳,那么很自然地就會(huì)想到用promise。
我之前是沒有自己寫過promise來用的泳叠,有些問題比較蠢作瞄,大佬們直接跳過吧。
先說一點(diǎn)基礎(chǔ)的內(nèi)容
我以前一直沒弄明白new promise的傳入的函數(shù)和resolve危纫、rejsect到底是個(gè)什么關(guān)系宗挥。我想很多初學(xué)者應(yīng)該也和我一樣沒有捋清楚。
一個(gè)個(gè)來
executor
就是傳入的這個(gè)function种蝶,MDN上這么說
Promise構(gòu)造函數(shù)執(zhí)行時(shí)立即調(diào)用executor 函數(shù)
也就是說契耿,new了之后這個(gè)function就執(zhí)行了
resolve/reject
這兩是函數(shù),調(diào)用了之后就會(huì)分別走向fulfilled和reject狀態(tài)螃征。這兩個(gè)函數(shù)是要自己在promise邏輯中調(diào)用的搪桂,參數(shù)會(huì)傳到then的回調(diào)中
用promise處理小程序回調(diào)
這位老哥給了一個(gè)我覺得不錯(cuò)的方法
https://segmentfault.com/a/1190000013150196#articleHeader3
function promisify (api) {
return (options, ...params) => {
return new Promise((resolve, reject) => {
api(Object.assign({}, options, { success: resolve, fail: reject }), ...params);
});
}
}
原理還是很簡(jiǎn)單的, 利用了剛剛說的resolve/reject函數(shù)的調(diào)用參數(shù)會(huì)傳遞then中對(duì)應(yīng)的函數(shù)這個(gè)特性. 然后做了一些處理保證其他的值也能傳進(jìn)來.
使用這個(gè)封裝之后, 小程序回調(diào)的傳值就可以直接在then里面使用了
注意:
這個(gè)方法適用于有success回調(diào)的接口, 其他的沒用也沒必要用
為什么要返回一個(gè)函數(shù)而不直接返回promise對(duì)象
因?yàn)橐邮掌渌膮?shù), 否則封裝就是很拙劣的.
如果直接返回promise對(duì)象的話得這么寫
function promisify_no_func(api, options, ...params) {
return new Promise((resolve, reject) => {
api(Object.assign({}, options, { success: resolve, fail: reject }), ...params);
});
}
對(duì)比一下調(diào)用的感覺
// 返回函數(shù)
var api = promisify(wx.api)
api({opt}, param)().then(res => console.log(res))
// 返回promise對(duì)象
promisify_no_func(wx.api, {opt}, param).then(res => console.log(res))
顯然是前者更合適的
下一個(gè)問題
我想拿到promise返回的值怎么辦???
我決定專門寫一篇文章講一講