JS - Promise使用

一、什么是Promise

A Promise is an object representing the eventual completion or failure of an asynchronous operation.

從官方文檔我們可知

  • Promise是ES6新增的一個對象,一個構造函數(shù)
  • 用于多層次異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數(shù)地獄

1.1 Promise的三種狀態(tài)

  • pending: 初始狀態(tài),既不是成功,也不是失敗狀態(tài)。
  • fulfilled: 意味著操作成功完成。
  • rejected: 意味著操作失敗。

什么意思呢?三種狀態(tài)對應異步操作的三種情況,比如發(fā)送一次ajax請求,初始等待時,狀態(tài)為pending,ajax請求成功時,調用Promise內置函數(shù)resolve(), Promise狀態(tài) => fulfilled,請求失敗時,調用函數(shù)reject(),Promise狀態(tài) => rejected

二、Promise 基本用法

var Promise: PromiseConstructor
new <any>(executor: (resolve: (value?: any) => void, reject: (reason?: any) => void) => void) => Promise<any>

從語法上來看,Promise 是一個構造函數(shù),需要傳入一個參數(shù)executor函數(shù).
new Promise 時會調用executor 函數(shù), executor函數(shù)也有兩個參數(shù).resolve 和 reject,這兩個參數(shù)也是函數(shù),調用resolve或reject時,分別將promise的狀態(tài)改為fulfilled(完成)或rejected(失?。?。Promise 狀態(tài)只能唯一

2.1 Promise基本使用

下面來看兩個例子
(1)

var promise = new Promise((resolve, reject) => {
  if(異步請求成功){
    resolve()
  }else{
    reject()
  }
})

promise.then(()=>{
  //success
},()=>{
  //failure
})

(2) 用定時器setTimeout模擬異步請求成功

function ajax() {
  return new Promise(resolve => {
    setTimeout(resolve, 1000)
  })
}

ajax().then(() => {
  console.log("request success") //success
})

上面代碼表示,如果異步操作成功,就調用resolve()方法,就會執(zhí)行Promise實例then()方法的第一個回調函數(shù),如果失敗則調用then()方法的第二個回調函數(shù).

2.2 Promise使用時傳參

resolve()和reject()函數(shù)調用時可傳參,傳入的參數(shù)會被Promise實例 then和catch方法捕獲.

var promise = new Promise((resolve, reject) => {
  if (異步請求成功) {
    resolve("success")
  } else {
    reject("error")
  }
})

promise.then( res => {
    res // success
})
//捕獲異??捎胏atch()方法
promise.catch( err => {
    err // error
})

2.3 Promise 鏈式調用

Promise強大的地方在于此,如果發(fā)送一個異步請求,又返回另外一個異步請求時,可用鏈式調用

new Promise((resolve) => {
  resolve(1)
}).then((res) => {
  return new Promise((resolve) => {
    resolve(res+2)
  })
}).then((res) => {
  return new Promise((resolve) => {
    resolve(res+3)
  })
}).then((res) => {
  res // 6
})

當對異步請求返回結果res的操作簡單操作時,可用Promise.resolve()簡寫

new Promise((resolve) => {
  resolve(1)
}).then((res) => {
  return Promise.resolve(res+2)
}).then((res) => {
  return Promise.resolve(res+3)
}).then((res) => {
  res // 6
})

還有一種更簡單的語法糖

new Promise((resolve) => {
  resolve(1)
}).then((res) => {
  return res + 2
}).then((res) => {
  return res + 3
}).then((res) => {
  res // 6
})

2.4 鏈式調用注意事項

鏈式調用(chaining)按序執(zhí)行,有以下約定,使用時要多注意.

  • 在本輪 事件循環(huán)運行完成之前,回調函數(shù)是不會被調用的。
  • 即使異步操作已經完成(成功或失?。?,在這之后通過 then()添加的回調函數(shù)也會被調用
  • 通過多次調用then() 可以添加多個回調函數(shù),它們會按照插入順序執(zhí)行

看下面的例子

new Promise((resolve) => {
  resolve()
}).then(() => {
  console.log('execute') // execute
}).then(() => {
  console.log('execute') // execute
}).then(() => {
  console.log('execute') // execute
})

只要觸發(fā)了一次resolve(),鏈上的所有then都會被調用,當然后面的沒有調用resolve自然拿不到操作數(shù).

new Promise((resolve) => {
  resolve()
}).then(() => {
  console.log('execute') // execute
}).then(() => {
  console.log('execute') // execute
}).catch(()=>{
  console.log('execute') // no execute
}).then(()=>{
  console.log('execute') // execute
})

中間穿插catch(),其后的then也會被執(zhí)行

new Promise((resolve,reject) => {
  reject()
}).then(() => {
  console.log('execute') // no execute
}).catch(()=>{
  console.log('execute') // execute
}).then(() => {
  console.log('execute') // execute
})

new Promise((resolve,reject) => {
  reject()
}).then(() => {
  console.log('execute') // no execute
}).catch(()=>{
  console.log('execute') // execute
}).then(() => {
  console.log('execute') // execute
})

捕獲reject()后的then會被執(zhí)行


new Promise((resolve) => {
  resolve()
}).then(() => {
  console.log("execute")  // execute
  throw new Error()
}).then(() => {
  console.log("execute") // no execute
}).catch(() => {
  console.log("execute") // execute
}).then(() => {
  console.log("execute") // execute
})

情況有很多種,怎么去理解呢,看下面這個例子

const arr = ["foo","bar"]
arr.forEach(async (item) => {
  const res = await new Promise(resolve=>{
    resolve("why")
  }).then(res=>{
    return res
  })
  console.log(res);
  console.log(item);
// why、foo、why、bar
})

res 會拿到 Promise resolve()的操作數(shù)
輸出結果為 why、foo、why、bar


把return res 注釋發(fā)現(xiàn),仍然可以輸出結果,相當于執(zhí)行了 Promise.resolve(),catch()中同理

const arr = ["foo","bar"]
arr.forEach(async (item) => {
  const res = await new Promise(resolve=>{
    resolve("why")
  }).then(res=>{
    // return res 
    // Promise.resolve()
  })
  console.log(res);
  console.log(item);
// undefined、foo、undefined、bar
})

總結 :then(),catch()觸發(fā)后,會返回一個空的 resolve()

三、Promise內置方法

3.1 Promise.all()

Promise.all(iterable) 方法返回一個 Promise 實例,此實例在 iterable迭代器 參數(shù)內所有的 promise 都“完成(resolved)”或參數(shù)中不包含 promise 時回調完成(resolve);如果參數(shù)中 promise 有一個失?。╮ejected),此實例回調失?。╮eject),失敗的原因是第一個失敗 promise 的結果。

var p1 = Promise.resolve("res1")
var p2 = Promise.resolve("res2")

Promise.all([p1, p2]).then((res) => {
  res // ["res1", "res2"]
})

捕獲異常結果err為響應速度快的

var p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("err1")
  }, 1000)
})
var p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("err2")
  }, 2000)
})
Promise.all([p1, p2]).catch((err) => {
 err //err1
})

3.2 Promise.race()

  • race 函數(shù)返回一個 Promise,它將與第一個傳遞的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失敗(rejects),這要取決于第一個完成的方式是兩個中的哪個。
  • 如果傳的迭代是空的,則返回的 promise 將永遠等待。
  • 如果迭代包含一個或多個非承諾值和/或已解決/拒絕的承諾,則 Promise.race 將解析為迭代中找到的第一個值。
var p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("res1")
  }, 3000)
})
var p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("err2")
  }, 2000)
})
Promise.race([p1, p2])
.then((res)=>{
  console.log(res);
}).catch((err)=>{
  console.log(err); //err2
})

then,catch只會調用二者其一,并且取決于迭代器中參數(shù)的響應速度

3.3 Promise.allSettled()

Promise.allSettled()方法返回一個在所有給定的promise已被決議或被拒絕后決議的promise,并帶有一個對象數(shù)組,每個對象表示對應的promise結果

var p1 = Promise.resolve("res1")
var p2 = Promise.reject("res2")

Promise.allSettled([p1, p2]).then((res) => {
  res   // [{status: "fulfilled", value: "res1"},
        //  {status: "rejected", reason: "res2"}]
})

返回一個對象數(shù)組,包含iterator所有參數(shù)Promise的狀態(tài)和結果

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容