Promise
簡介
- 主要用於非同步操作,是一個由 asynchronous function return 的物件
- 用來表示一個異步操作的最终完成(或失敗)及其结果值
- 代理一個建立時不用預先得知結果的值
- 解決
callback hell
的問題......我的超人
語法
- 只能使用
new
關鍵字創建
new Promise(executor)
Promise 構造函式包含兩個參數:
resolve
- 將 promise 的狀態從 pending 更改為 fulfilled(成功)
- 將非同步函式執行後的結果作為參數傳送給
.then( )
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
- 後續的
resolve
和reject
都會被忽略
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 方法
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"});
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
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