Promise

簡介

  • 主要用於非同步操作,是一個由 asynchronous function return 的物件
  • 用來表示一個異步操作的最终完成(或失敗)及其结果值
  • 代理一個建立時不用預先得知結果的值
  • 解決callback hell的問題......我的超人

語法

  • 只能使用new關鍵字創建
new Promise(executor)

Promise 構造函式包含兩個參數:

  1. resolve
  • 將 promise 的狀態從 pending 更改為 fulfilled(成功)
  • 將非同步函式執行後的結果作為參數傳送給.then( )
  1. reject
  • 將 promise 的狀態從 pending 更改為 rejected (失敗)
  • 將錯誤訊息作為參數傳送給.catch( )

Promise 狀態

  • pending:事件運行中,尚未取得結果(初始狀態)
  • resolved:事件已經執行完畢且成功操作,回傳 resolve 的結果(該承諾已經被實現 fulfilled)
  • rejected:事件已經執行完畢但操作失敗,回傳 rejected 的結果
promise()  .then((success) => {    console.log(success)  })  .catch((fail) => {    console.log(fail)  })

範例:創建一個 promise

const getUser = new Promise((resolve, reject) => {  // Do some async task  setTimeout(() => {    let error = false    if (!error) {      resolve({ name: 'Blur', age: 40 })    } else {      reject('Error: Something went wrong...')    }  }, 1000)})getUser  .then((user) => console.log(user))  .catch((error) => console.log(error))  .finally(() => console.log('The promise has been resolved or rejected'))

🤔 創建 Promise 構造函式,executor內的程式碼是會立即執行的

範例 1

console.log('開始')const myPromise = new Promise((resolve, reject) => {  console.log('Promise內部 (同步執行)')  resolve()})console.log('結束')// output// 開始// Promise內部 (同步執行)// 結束

範例 2

// This is a JavaScript Quiz from BFE.devconsole.log(1)const promise = new Promise((resolve) => {  console.log(2)  resolve()  console.log(3)})console.log(4)promise  .then(() => {    console.log(5)  })  .then(() => {    console.log(6)  })console.log(7)setTimeout(() => {  console.log(8)}, 10)setTimeout(() => {  console.log(9)}, 0)// 出現順序:1 2 3 4 7 5 6 9 8

🤔 如果有兩個resolve

  • 一開始調用了resolve(1),Promise 的狀態從Pending被修改成fulfilled
  • 後續的resolvereject都會被忽略
new Promise((resolve, reject) => {  resolve(1)  resolve(2)  reject('error')}).then(  (value) => {    console.log(value)  },  (error) => {    console.log('error')  })// output// 1

範例:決定非同步函式的執行順序

  • 希望執行順序: fun1 => fun2 => fun3
// 使用Promisefunction fun1() {  return new Promise((resolve, reject) => {    setTimeout(() => {      resolve('hello')    }, 3000)  })}function fun2(data) {  return new Promise((resolve, rejcet) => {    setTimeout(() => {      resolve(data)    }, 2000)  })}function fun3(data) {  return new Promise((resolve, reject) => {    console.log(data)  })}fun1()  .then(fun2)  .then(fun3)  .catch((error) => {    console.log(error)  })// 執行fun1,3秒後將resolve的結果'hello'作為參數回傳給fun2// fun2接收到'hello',2秒後將resolve的結果'hello'作為參數回傳給fun3// fun3 印出 'hello'
// 不使用Promsiefunction fun1(callback) {  setTimeout(() => {    callback('hello')  }, 3000)}function fun2(data, callback) {  setTimeout(() => {    callback(data)  }, 2000)}function fun3(data) {  console.log(data)}//fun1((resultFromFun1) => {  fun2(resultFromFun1, (resultFromFun2) => {    fun3(resultFromFun2)  })})

範例:傳入的數字是否大於 5

//exampleconst getSomeData = (num) => {  return new Promise((resolve, reject) => {    if (num > 5) {      resolve('resolve number > 5')    }    reject('reject number < 5')  })}getSomeData(10)  .then((data) => {    return getSomeData(0)  })  .catch((err) => {    return getSomeData(10)  })  .then((data) => {    console.log(data)  })  .finally(() => {    console.log('finally')  })

Promise 方法

  1. Promise.all
  • 目的:讓多個 promise 同時執行
  • 參數接受一個可迭代的物件,但通常會傳入 promise 組成的 array 作為參數
  • 每個 promise 完成時,resolve 的值會存入陣列中
  • 如果其中任何一個 Promise 失敗,會回傳第一個失敗的 Promise 物件

範例

//1const fetchPromise1 = fetch('url1');const fetchPromise2 = fetch('url2');const fetchPromise3 = fetch('url3');Promise.all([fetchPromise1,fetchPromise2,fetchPromise3])    //return 一個陣列    .then((responses) => {    responses.forEach((res)=> {        console.log(res)    }) }))//[result1, result2, result3]//2const promise1 = Promise.resolve(1);const promise2 = Promise.reject("Error");const promise3 = Promise.resolve(3);Promise.all([promise1, promise2, promise3]).catch((error) => {  console.log(error); // "Error"});
  1. Promise.any
  • 只要 Promise array 中的任何一個請求成功就執行.then(),並回傳這個 resolve 的結果
  • 如果所有 promises 都被拒絕,則執行.catch(),回傳 AggregateError,其中包含所有 Promise 的拒絕原因

範例

const promises = [Promise.resolve('hello'), Promise.reject('failed'), Promise.resolve('world')]Promise.any(promises)  .then((result) => console.log(result))  .catch((error) => console.error(error))// hello
  1. Promise.race
  • 任何一個"陣列傳入參數的 Promise 物件有解決,就會到下一步去

範例

const getSomeData = (num, time) => {  return new Promise((resolve, reject) => {    setTimeout(() => {      if (num > 0) {        resolve(`${num} > 0`)      } else {        reject(`${num} < 0`)      }    }, time)  })}Promise.race([getSomeData(10, 500), getSomeData(5, 1000)])  .then((data) => {    console.log(data)  })  .catch((err) => {    console.log(err)  })// '10 > 0'

async....await

  • Promise 的語法糖,提高程式碼可讀性,少寫很多.then()
  • 所有的 async function 都會 return 一個 Promise Object
  • async 宣告一個非同步函式,await 等待 Promise 的 resolve/reject
  • await 會回傳 Promise resolve/reject 的結果
  • 使用 try / catch 來區分 resolve/reject 要執行的區域
aysnc function myFunc() {    return 99;}let result = myFunc();console.log(result) //得到一個Promise物件//取得return的值result.then((data) => console.log(data)); //99

範例:發出 get 請求

async function fetchProduct(){    try{        const response = await fetch(url');        const data = await response.json();        console.log(data);    } catch(err){        console.log(err)    }  }fetchProduct();

範例:發出 post 請求

async function postData(url = '', data = {}) {  try {    const response = await fetch(url, {      method: 'POST',      headers: {        'Content-Type': 'application/json'      },      body: JSON.stringify(data)    })    return response.json()  } catch (error) {    console.error(error)    throw error // 再次抛出異常,以便上層代碼進行進一步處理  }}// 使用範例:postData('<https://example.com/api/posts>', { title: 'foo', body: 'bar', userId: 1 })  .then((data) => {    console.log(data)  })  .catch((error) => {    console.error(error)  })

範例:.then() & await 寫法比較

//使用awaitasync function getApiData() {  const data = await fetch(url)  const result = await data.json()  console.log(result)}//使用.thenasync function getApiData2() {  fetch(url)    .then((data) => data.json())    .then((result) => {      console.log(result)    })}

範例:使用箭頭函式

const getApiData = async () => {  const response = await fetch(url)    .then((res) => {      return res.json()    })    .then((data) => console.log(data))    .catch((err) => console.log(err))}

範例:try & catch 也可以使用在同步函式

function double(num) {  if (isNaN(num)) {    throw new Error(`${num} is not a number`)  }  return num * 2}try {  const x = double(3)  console.log(x) // 6} catch (err) {  console.log(err)}

參考資料

# JavaScript # ES6