1. 程式人生 > 其它 >ES6 Promise的理解應用

ES6 Promise的理解應用

技術標籤:JSjavascriptes6前端

本文是讀了阮一峰大神《ES6標準入門》-Promise 物件 後的一些個人的小總結

1. 什麼是promise?

1.1 重要概念

一個 Promise 必然處於以下幾種狀態之一:

  • 待定(pending): 初始狀態,既沒有被兌現,也沒有被拒絕。
  • 已兌現(fulfilled): 操作成功完成。
  • 已拒絕(rejected): 操作失敗。

待定狀態的 Promise 物件要麼會通過一個值被兌現(fulfilled),要麼會通過一個原因(錯誤)被拒絕(rejected)。

1.2 建立promise

  • promise物件是一個建構函式,用來生成promise例項
  • 該建構函式會把一個叫做“處理器函式”(executor function)的函式作為它的引數。這個“處理器函式”接受兩個函式resolve 和 reject 作為其引數。
  • 當非同步任務順利完成且返回結果值時,會呼叫 resolve 函式;而當非同步任務失敗且返回失敗原因(通常是一個錯誤物件)時,會呼叫reject 函式。
    • resolve:pending ——> resolved, 非同步操作的結果作為返回值
    • reject:pending ——> rejected, 錯誤原因作為返回值
  • promise例項生成以後,用 then 方法指定resolved狀態和rejected狀態的回撥函式

注:為了方便,resolved(表示 promise 已經處於已敲定(settled)狀態)指fulfilled狀態。

const promise = new Promise(function(resolve,reject){
  // some codes
  if(/*非同步操作成功*/){
    resolve(value);
  }else{
    reject(error);
  }
});
//then方法接受兩個回撥函式作為引數,第二個函式不一定提供
promise.then(function(value){
  //suc
},function(error){
  //fail
});

舉一個栗子:

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done'); //done是resolve函式的引數,這裡就是value
  });
}

timeout(3000).then((value) => {
  console.log(value);
});

上面栗子是說,過了指定時間(本例3000ms)後promise例項的狀態變成resolved,觸發then方法的回撥函式打印出結果(done)

2. promise的執行順序

  • promise新建後立即執行
  • then方法指定的回撥函式,在當前指令碼所有同步任務執行完成後才執行

直接來看栗子叭~~

console.log('Hi!');
let promise = new Promise(function(resolve, reject) {
  console.log('I am Promise'); //新建後立即執行
  resolve();
});
console.log("I'm tom");
promise.then(function() {
  console.log('resolved.'); //在當前指令碼所有同步任務執行完成後才執行
});
console.log("I'm a boy");

結果如下:
在這裡插入圖片描述

3. 使用promise可以避免回撥地獄

初次學習promise的時候,老師說promise可以避免回撥地獄。腦子裡面一直似懂非懂的,這下終於弄懂了來記錄一下。
再舉個栗子~~
我們現在想模擬一下接力跑的過程,我們如何用程式碼實現呢?

function f1(next){
  console.log("f1起跑...");
  setTimeout(()=>{
    console.log("f1到達,傳遞接力棒");
    next();
  },4000)
}
function f2(next){
  console.log("f2起跑...");
  setTimeout(()=>{
    console.log("f2到達,傳遞接力棒");
    next();
  },5000)
}
function f3(next){
  console.log("f3起跑...");
  setTimeout(()=>{
    console.log("f3到達終點");
    next();
  },3000)
}
f1(function(){
  f2(function(){
    f3(function(){
        console.log("比賽結束!");
    })
  })
})

通過上面程式碼,我們的確得到了預期的結果:
在這裡插入圖片描述
我們難以想象如果有更多的層層巢狀的回撥函式,我們還能這樣的輕鬆的、不出錯的寫出程式碼嗎?
這樣的程式碼可讀性低、編寫費勁、容易出錯,我們該如何解決呢?
來看看用promise如何解決:

function f1(next){
  return new Promise(function(resolve,reject){
    console.log("f1起跑...");
    setTimeout(()=>{
      console.log("f1到達,傳遞接力棒");
      resolve();
    },4000)
  }) 
}
function f2(next){
  return new Promise(function(resolve,reject){
    console.log("f2起跑...");
    setTimeout(()=>{
      console.log("f2到達,傳遞接力棒");
      resolve();
    },5000)
  }) 
}
function f3(next){
  return new Promise(function(resolve,reject){
    console.log("f3起跑...");
    setTimeout(()=>{
      console.log("f3到達終點");
      resolve();
    },3000)
  }) 
}
f1()
.then(f2)
.then(f3)
.then(()=>console.log("比賽結束!"));

總結:

  • 使用then方法依次指定多個回撥函式
  • 第一個回撥函式完成後,會將結果作為引數傳入第二個回撥函式
  • 採用鏈式的then,可以指定一組按照次序呼叫的回撥函式。若第一個回撥函式返回一個promise物件,這時後面的回撥函式會等待該promise物件狀態發生變化,才會被呼叫

還有一些promise的靜態方法沒有總結,下次補上~