ES6——舉個(gè)例子理解Promise的原理和使用

1. Promise 之前

1.1 回調(diào)函數(shù)

回調(diào)函數(shù):把函數(shù)A當(dāng)作參數(shù)傳遞給另一個(gè)函數(shù)B調(diào)用,那么A就是回調(diào)函數(shù)。
一些例子
具名回調(diào)

function 你有幾只狗(fn){
    fn('一只狗')
}
function 數(shù)狗(數(shù)量){
    console.log(數(shù)量)
}
你有幾只狗(數(shù)狗)   // 一只狗

匿名回調(diào)

function 你有幾只狗(fn){
    fn('一只狗')
}
你有幾只狗(function(數(shù)量){
console.log(數(shù)量) 
})         //  一只狗

常見(jiàn)的例子
jQuery中使用回調(diào)函數(shù),這里用的是匿名回調(diào)的方式

$("#btn").click(function(){
    console.log('點(diǎn)到我了')
})

1.2 回調(diào)地獄(回調(diào)缺點(diǎn)1)

回調(diào)地獄:指的是回調(diào)嵌套過(guò)多的情況,導(dǎo)致代碼很難被看懂。

let info = []
function 你有幾只狗(fn){
    fn('一只狗')
}
function 你有幾只貓(fn){
    fn('一只貓')
}
function 知道了(數(shù)量,callback){
    info.push(數(shù)量)
    console.log(info)
    if(callback){
        callback()
    }
}
// 開(kāi)始調(diào)用 如果比這再多幾層,就不容易看懂了
你有幾只狗(function(狗數(shù)){
    console.log(狗數(shù))
    知道了(狗數(shù), function(){
        你有幾只貓(function(貓數(shù)){
            console.log(貓數(shù))
            知道了(貓數(shù))
        })
    })
})

1.3 不使用Promise,如何解決

利用具名函數(shù)代替匿名函數(shù)

let info = []
function 你有幾只狗(fn){
    fn('一只狗')
}
function 你有幾只貓(fn){
    fn('一只貓')
}
function 知道了(數(shù)量,callback){
    info.push(數(shù)量)
    console.log(info)
    if(callback){
        callback()
    }
}
function 告訴你貓的個(gè)數(shù)(貓數(shù)){
    console.log(貓數(shù))
    知道了(貓數(shù))
}
function 繼續(xù)數(shù)(){
    你有幾只貓(告訴你貓的個(gè)數(shù))
}
function 告訴你狗的個(gè)數(shù)(狗數(shù)){
    console.log(狗數(shù))
    知道了(狗數(shù), 繼續(xù)數(shù))
}
你有幾只狗(告訴你狗的個(gè)數(shù))  // 好像也沒(méi)好到哪去。。。

1.4 回調(diào)方式各不相同,需要單獨(dú)記憶(回調(diào)缺點(diǎn)2)

readFile('C:\\1.txt',function (error, data) {   // node.js 讀取文件方法中的回調(diào)
        if(error) {
            console.log('成功')
            console.log(data.toString())
        } else {
            console.log('讀取文件失敗')
        }
    })

$.ajax({                              // jQuery中ajax方法中的回調(diào)
    url:'/2.txt'
    success: function(response) {
        console.log('成功')
    },
    error: function(){
        console.log('失敗')
    }
})

2. Promise 的目的

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

3. Promise 的原理

3.1 實(shí)現(xiàn)原理

ES6 規(guī)定,Promise對(duì)象是一個(gè)構(gòu)造函數(shù),用來(lái)生成Promise實(shí)例。通過(guò)在函數(shù)內(nèi)部return 一個(gè) Promise對(duì)象的實(shí)例,這樣就可以使用Promise的屬性和方法進(jìn)行下一步操作了。

function 函數(shù)名(){
    return new Promise(function(resolve, reject) {
        // ... some code
          if (/* 異步操作成功 */){
            resolve(value);   // 異步操作成功時(shí)調(diào)用,把結(jié)果作為參數(shù)傳遞出去
          } else {
            reject(error);     // 異步失敗時(shí)調(diào)用,把錯(cuò)誤作為參數(shù)傳遞出去
          }
        
    })
}

3.2 調(diào)用邏輯

3.2.png

S1和E1兩個(gè)都沒(méi)有報(bào)錯(cuò),執(zhí)行S2(resolve執(zhí)行,系統(tǒng)認(rèn)為搞定了,沒(méi)報(bào)錯(cuò))
S1和E1任何一個(gè)有報(bào)錯(cuò),執(zhí)行E2(reject執(zhí)行,系統(tǒng)認(rèn)為沒(méi)搞定,報(bào)錯(cuò)了)

4. Promise 的使用

4.1 Promise 的屬性與方法

屬性
Promise.prototype 表示 Promise 構(gòu)造器的原型
方法
Promise.prototype.then()
返回一個(gè) Promise 。它最多需要有兩個(gè)參數(shù):Promise 的成功和失敗情況的回調(diào)函數(shù)。
Promise.prototype.catch()
返回一個(gè)Promise,并且處理拒絕的情況。等價(jià)于Promise.prototype.then(undefined, onRejected)
Promise.prototype.finally()
finally() 方法返回一個(gè)Promise,在執(zhí)行then()和catch()后,都會(huì)執(zhí)行finally指定的回調(diào)函數(shù)。避免同樣的語(yǔ)句需要在then()和catch()中各寫(xiě)一次的情況。
Promise.all(iterable)
返回一個(gè) Promise 實(shí)例,iterable參數(shù)內(nèi)所有的 promise 都resolved后,才回調(diào)完成resolve。
Promise.race(iterable)
返回一個(gè) promise ,并伴隨著 promise對(duì)象解決的返回值或拒絕的錯(cuò)誤原因, 只要 iterable 中有一個(gè) promise 對(duì)象"解決(resolve)"或"拒絕(reject)"。
Promise.resolve()
返回一個(gè)以給定值解析后的Promise對(duì)象。但如果這個(gè)值是個(gè)thenable(即帶有then方法),返回的promise會(huì)“跟隨”這個(gè)thenable的對(duì)象,采用它的最終狀態(tài)(指resolved/rejected/pending/settled);如果傳入的value本身就是promise對(duì)象,則該對(duì)象作為Promise.resolve方法的返回值返回;否則以該值為成功狀態(tài)返回promise對(duì)象。
Promise.reject()
返回一個(gè)帶有拒絕原因reason參數(shù)的Promise對(duì)象。

4.2 將回調(diào)地獄中的例子,改寫(xiě)為Promise的形式

4.2-1.png

可以看到使用 Promise后,邏輯變得非常直觀(guān)
寫(xiě)得更完整一些
4.2-2.png

Promise套Promise時(shí),也就是Promise鏈的時(shí)候——注意信息的傳遞
一個(gè)失敗的例子,當(dāng)我們使用Promise鏈的時(shí)候,如果每一步都需要上一步的數(shù)據(jù)時(shí),就需要傳參,成功通過(guò)resolve傳參,失敗通過(guò)reject傳參,如果忘記傳參,就得不到想要的結(jié)果。
resolve把成功的數(shù)據(jù)返回給下一個(gè)回調(diào)
reject把失敗的數(shù)據(jù)返回給下一個(gè)回調(diào)。
4.2-3.png

給這里的resolve傳一個(gè)參
4.2-4.png

改成失敗的例子
先不給reject傳參,如果失敗的話(huà),下一個(gè)回調(diào)拿不到數(shù)據(jù)
4.2-5.png

給 reject傳參
4.2-6.png

我們可以看到,即使是走的失敗回調(diào),下一個(gè)成功回調(diào)還是執(zhí)行了,由于 不知道() 默認(rèn)返回undefined, 相當(dāng)于失敗已經(jīng)處理了,在成功和失敗都被處理的情況下,下一個(gè)回調(diào)會(huì)執(zhí)行的。
改成符合預(yù)期的,即失敗不調(diào)用。
4.2-7.png

失敗不調(diào)用的簡(jiǎn)寫(xiě)形式
4.2-8.png

上述情況執(zhí)行后 .then(除了狗呢)里面的成功回調(diào)沒(méi)有執(zhí)行,我們?cè)黾右粋€(gè)失敗回調(diào)看看
4.2-9.png

同樣也可以返回 resolve,讓后面成功回調(diào)可以執(zhí)行
4.2-10.png

4.3 應(yīng)用

加載圖片
將圖片的加載寫(xiě)成一個(gè)Promise,一旦加載完成,Promise的狀態(tài)就發(fā)生變化。

const preloadImage = function (path) {
  return new Promise(function (resolve, reject) {
    const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = path;
  });
};

Generator 函數(shù)與 Promise 的結(jié)合(詳情見(jiàn)參考鏈接,阮一峰的教程)

5. 干掉Promise中的回調(diào)

5.1 await

成功的情況


5.1-1.png

失敗的情況
利用 try catch


5.1-2.png

await 配合 try catch使用,比較完整

6. 總結(jié)

能利用Promise對(duì)象,把普通函數(shù)改成返回Promise的形式,解決回調(diào)地獄的問(wèn)題。
明白Promise的成功失敗調(diào)用邏輯,可以靈活的進(jìn)行調(diào)整。
理解核心知識(shí),先用起來(lái),慢慢整合吸收知識(shí)。

7. 參考鏈接

?著作權(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)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,837評(píng)論 1 56
  • 本文適用的讀者 本文寫(xiě)給有一定Promise使用經(jīng)驗(yàn)的人,如果你還沒(méi)有使用過(guò)Promise,這篇文章可能不適合你,...
    HZ充電大喵閱讀 7,458評(píng)論 6 19
  • Promise 的含義 一句話(huà)概括一下promise的作用:可以將異步操作以同步操作的流程表達(dá)出來(lái),避免了層層嵌套...
    雪萌萌萌閱讀 5,661評(píng)論 0 7
  • 前言 本文旨在簡(jiǎn)單講解一下javascript中的Promise對(duì)象的概念,特性與簡(jiǎn)單的使用方法。并在文末會(huì)附上一...
    _暮雨清秋_閱讀 2,315評(píng)論 0 3
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說(shuō),Pr...
    雨飛飛雨閱讀 3,491評(píng)論 0 19

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