點燈坊

失くすものさえない今が強くなるチャンスよ

Promise 之 Promise Constructor

Sam Xiao's Avatar 2020-07-09

除了使用 Promise.resolve()Promise.reject() 建立 Promise 外,也可使用 Promise Constructor 建立 Promise,其 Argument 為 Executor Function,提供了 resolve()reject(),可用來建立 Fulfilled Promise 與 Rejected Promise。

Version

macOS Catalina 10.15.5
VS Code 1.46.1
Quokka 1.0.307
ECMAScript 2015

Promise Constructor

let f = ms => x => new Promise((resolve, reject) => {
  let inc = _ => {
    let result = x + 1
    
    return (result % 2) ?
      resolve(`fulfilled: ${result}`) :
      reject(`rejected: ${result}`)
  }

  setTimeout(inc, ms)
})

f(3000)(1) // ?
f(3000)(2) // ?

第 2 行

let inc = _ => {
  let result = x + 1
    
  return (result % 2) ?
    resolve(`fulfilled: ${result}`) :
    reject(`rejected: ${result}`)
}

inc() 是 synchronous function,若 + 1 結果是 奇數,則回傳 Fulfilled Promise;若結果為 偶數,則回傳 Rejected Promise。

第 10 行

setTimeout(inc, ms)

重點是 inc() 並不是立即執行,而是 setTimeout()3 秒才執行,所以回傳是 Promise。

若要在 asynchronous function 產生 Promise,只靠 Promise.resolve()Promise.reject() 寫不出來,必須使用 Promise Constructor,透過其 executor function 傳進 resolve()reject(),則可在 setTimeout() 的 callback 內由 resolve()reject() 建立 Promise 回傳。

constructor000

FileReader

let toBase64 = file => new Promise((resolve, reject) => {
  let fileReader = new FileReader
  fileReader.onload = _ => resolve(fileReader.result)
  fileReader.onerror = e => reject(e)
  fileReader.readAsDataURL(file)
})

toBase(x) // ?

Web API 的 FileReader 可將檔案轉成 Base64 String,但為 Event-based function,該如何改成 Promise-based 呢 ?

將檔案傳入 FileReader.readAsDataURL(),會 asynchronous 在 onload event 以 fileReader.result 獲得 Base64 String,在 onerror event 取得 Error Object。

這種以 Event-based function 就特別適合使用 Promise Constructor,在 onload event 以 resolve()fileReader.result 包成 Fulfilled Promise,並在 onerror event 以 reject() 將 Error Object 包成 Rejected Promise。

Conclusion

  • 有兩個場景特別適合使用 Promise Constructor:
    • 需同時產生 Fulfilled Promise 與 Rejected Promise 時
    • 須將 Callback-based function 改成 Promise-based function 時,如 setTimeout()
    • 需將 Event-based function 改成 Promise-based function 時,如 FileReader

Reference

Marius Schulz, Create a New Promise in JavaScript with Promise Constructor
MDN, Promise