1. 程式人生 > 其它 >為什麼要使用Promise,Promise的優點

為什麼要使用Promise,Promise的優點

1.指定回撥函式的方式更加靈活:
舊的: 必須在啟動非同步任務前指定 promise: 啟動非同步任務 => 返回promie物件 => 給promise物件繫結回撥函式(甚至可以在非同步任務結束後指定) `

假設現在有一個名為 createAudioFileAsync() 的函式,如果給出一些配置和兩個回撥函式,這個函式能非同步地生成音訊檔案。一個回撥函式是檔案成功建立時的回撥,另一個則是出現異常時的回撥。

  • 不使用Promise,回撥函式必須先指定


// 成功的回撥函式
function successCallback (result) {
    console.log('聲音檔案建立成功: ' + result)
}
// 失敗的回撥函式
function failureCallback (error) {
    console.log('聲音檔案建立失敗: ' + error)
}
/* 1.1 使用純回撥函式 */
createAudioFileAsync(audioSettings, successCallback, failureCallback)
  • 使用Promise


const promise = createAudioFileAsync(audioSettings)
promise.then(successCallback, failureCallback)
 
// 可簡寫為
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

可以在非同步操作完成後再指定回撥函式



setTimeout(() => {
    promise.then(successCallback, failureCallback)
}, 3000)

2.支援鏈式呼叫(將非同步操作以同步操作的流程表達出來), 可以解決回撥地獄問題
什麼是回撥地獄? 回撥函式巢狀呼叫, 外部回撥函式非同步執行的結果是巢狀的回撥函式執行的條件
回撥地獄的缺點? 不便於閱讀 / 不便於異常處理
解決方案? promise鏈式呼叫
終極解決方案? async/await

  1. 回撥地獄
doSomething(function (result) {
    doSomethingElse(result, function (newResult) {
        doThirdThing(newResult, function (finalResult) {
            console.log('Got the final result: ' + finalResult)
        }, failureCallback)
    }, failureCallback)
}, failureCallback)
  1. 使用promise的鏈式呼叫解決回撥地獄
 doSomething().then(function (result) {
         return doSomethingElse(result)
     })
     .then(function (newResult) {
         return doThirdThing(newResult)
     })
     .then(function (finalResult) {
         console.log('Got the final result: ' + finalResult)
     })
     .catch(failureCallback)
======
// 箭頭函式寫法
doSomething()
    .then(result => doSomethingElse(result))
    .then(newResult => doThirdThing(newResult))
    .then(finalResult => {
        console.log(`Got the final result: ${finalResult}`)
    })
    .catch(failureCallback)
  1. async/await: 回撥地獄的終極解決方案
async function request () {
    try {
        const result = await doSomething()
        const newResult = await doSomethingElse(result)
        const finalResult = await doThirdThing(newResult)
        console.log('Got the final result: ' + finalResult)
    } catch (error) {
        failureCallback(error)
    }
}

Promise的缺點:

  • 無法取消Promise,一旦新建它就會立即執行,無法中途取消。
  • 如果不設定回撥函式,Promise內部丟擲的錯誤,不會反應到外部。
  • 當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行會報錯,因為x沒有宣告
    resolve(x + 2);
  });
};
 
someAsyncThing().then(function() {
  console.log('everything is great');
});
 
setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123

上面程式碼中,someAsyncThing函式產生的 Promise 物件,內部有語法錯誤。瀏覽器執行到這一行,會打印出錯誤提示ReferenceError: x is not defined,但是不會退出程序、終止指令碼執行,2 秒之後還是會輸出123。這就是說,Promise 內部的錯誤不會影響到 Promise 外部的程式碼,通俗的說法就是“Promise 會吃掉錯誤”。