[新手向] Promise課程筆記整理

promise-2.png

MDN Promise 文檔javascript

  • Promise 及其做用java

    • ES6 內置類
    • 回調地獄:AJAX 的串行和並行
  • Promise 的 executor 函數和狀態ajax

    • executor
    • Promise 狀態編程

      • pending 初始狀態
      • fulfilled 操做成功完成
      • rejected 操做失敗
  • Promise 中的 then 和 catch設計模式

    • then(func1,func2) / then(func)
    • catch(func)
    • then 鏈機制
  • Promise 中其它經常使用方法數組

    • Promise.all
    • Promise.race
    • Promise.reject (選)
    • Promise.resolve (選)

一、Promise 及其做用

1-一、ES6 內置類

Promise 的誕生就是爲了解決異步請求中的回調地獄問題:它是一種設計模式,ES6 中提供了一個 JS 內置類 Promise,來實現這種設計模式promise

function ajax1() {
  return new Promise((resolve) => {
    $.ajax({
      url: "/url1",
      // ...
      success: resolve,
    });
  });
}

function ajax2() {
  return new Promise((resolve) => {
    $.ajax({
      url: "/url2",
      // ...
      success: resolve,
    });
  });
}

function ajax3() {
  return new Promise((resolve) => {
    $.ajax({
      url: "/url3",
      // ...
      success: resolve,
    });
  });
}

ajax1()
  .then((result) => {
    return ajax2(result.map((item) => item.id));
  })
  .then((result) => {
    return ajax3();
  })
  .then((result) => {});

1-二、回調地獄:AJAX 的串行和並行

回調地獄:上一個回調函數中繼續作事情,並且繼續回調(在真實項目的 AJAX 請求中常常出現回調地獄)=> 異步請求、不方便代碼的維護dom

二、Promise 的 executor 函數和狀態

2-一、executor

new Promise([executor]) ,[executor]執行函數是必須傳遞的異步

Promise 是用來管理異步編程的,它自己不是異步的。async

new Promise 的時候會當即把 executor 函數執行(只不過咱們通常會在 executor 函數中處理一個異步操做)

// new Promise 的時候會當即把 executor 函數執行
let p1 = new Promise(() => {
  setTimeout((_) => {
    console.log(1);
  }, 1000);
  console.log(2);
});
console.log(3);

// 2.3.1

2-二、Promise 狀態

Promise {<pending>}
    __propt__:Promise
    [[PromiseStatus]]:"pending"
    [[PromiseValue]]:"undefined"

// Promise 自己有一個 Value 值,用來記錄成功的結果(或者是失敗的緣由的) =>[[PromiseValue]]

Promise 自己有三個狀態 => [[PromiseStatus]]

  • pending 初始狀態
  • fulfilled 操做成功完成
  • rejected 操做失敗
let p1 = new Promise((resolve, reject) => {
  setTimeout((_) => {
    // 通常會在異步操做結束後,執行resolve/reject函數,執行這兩個函數中的一個,均可以修改Promise的[[PromiseStatus]]/[[PromiseValue]]
    // 一旦狀態被改變,在執行resolve、reject就沒有用了
    resolve("ok");
    reject("no");
  }, 1000);
});

三、Promise 中的 then 和 catch

3-一、then(func1,func2) / then(func)

new Promise 的時候先執行 executor 函數,在這裏開啓了一個異步操做的任務(此時不等:把其放入到 EventQuque 任務隊列中),繼續執行

p1.then 基於 then 方法,存儲起來兩個函數(此時這兩個函數尚未執行);當 executor 函數中的異步操做結束了,基於 resolve/reject 控制 Promise 狀態,從而決定執行 then 存儲的函數中的某一個

let p1 = new Promise((resolve, reject) => {
  setTimeout((_) => {
    let ran = Math.random();
    console.log(ran);
    if (ran < 0.5) {
      reject("NO!");
      return;
    }
    resolve("OK!");
  }, 1000);
});
// then:設置成功或者失敗後處理的方法
// Promise.prototype.then([resolvedFn],[rejectedFn])
p1.then(
  // 成功函數
  (result) => {
    console.log(`成功:` + result);
  },
  // 失敗函數
  (reason) => {
    console.log(`失敗:` + reason);
  }
);

resolve/reject 的執行,不管是否放到一個異步操做中,都須要等待 then 先執行完,把方法存儲好,纔會在更改狀態後執行 then 中對應的方法 => 此處是一個異步操做(因此不少人說 Promise 是異步的),並且是微任務操做

let p1 = new Promise((resolve, reject) => {
  resolve(100);
});
p1.then(
  (result) => {
    console.log(`成功:` + result);
  },
  (reason) => {
    console.log(`失敗:` + reason);
  }
);
console.log(3);

// 3
// 成功:100

建立一個狀態爲成功/失敗的 PROMISE 實例

這樣的寫法也能夠被這種寫法代替

Promise.resolve(100) | Promise.reject(0)

then 中也能夠只寫一個或者不寫函數 ( .then(fn) | .then(null,fn) )

3-二、catch(func)

Promise.prototype.catch(fn)

===> .then(null,fn)

Promise.resolve(10)
  .then((result) => {
    console(a); //=>報錯了
  })
  .catch((reason) => {
    console.log(`失敗:${reason}`);
  });

3-三、then 鏈機制

then 方法結束都會返回一個新的 Promise 實例(then 鏈)

p1 這個 new Promise 出來的實例,成功或者失敗,取決於 executor 函數執行的時候,執行的是 resolve 仍是 reject 決定的,再或者 executor 函數執行發生異常錯誤,也是會把實例狀態改成失敗的

p2/p3 這種每一次執行 then 返回的新實例的狀態,由 then 中存儲的方法執行的結果來決定最後的狀態(上一個 THEN 中某個方法執行的結果,決定下一個 then 中哪個方法會被執行)

=> 不管是成功的方法執行,仍是失敗的方法執行(then 中的兩個方法),凡是執行拋出了異常,則都會把實例的狀態改成失敗

=> 方法中若是返回一個新的 Promise 實例,返回這個實例的結果是成功仍是失敗,也決定了當前實例是成功仍是失敗

=> 剩下的狀況基本上都是讓實例變爲成功的狀態 (方法返回的結果是當前實例的 value 值:上一個 then 中方法返回的結果會傳遞到下一個 then 的方法中)

let p1 = new Promise((resolve, reject) => {
  resolve(100);
});
let p2 = p1.then(
  (result) => {
    console.log("成功:" + result);
    return result + 100;
  },
  (reason) => {
    console.log("失敗:" + reason);
    return reason - 100;
  }
);
let p3 = p2.then(
  (result) => {
    console.log("成功:" + result);
  },
  (reason) => {
    console.log("失敗:" + reason);
  }
);

then 鏈式調用:

Promise.resolve(10)
  .then(
    (result) => {
      console.log(`成功:${result}`);
      return Promise.reject(result * 10);
    },
    (reason) => {
      console.log(`失敗:${reason}`);
    }
  )
  .then(
    (result) => {
      console.log(`成功:${result}`);
    },
    (reason) => {
      console.log(`失敗:${reason}`);
    }
  );

遇到一個 then,要執行成功或者失敗的方法,若是此方法並無在當前 then 中被定義,則順延到下一個對應的函數

Promise.reject(10)
  .then((result) => {
    console.log(`成功:${result}`);
    return result * 10;
  })
  .then(null, (reason) => {
    console.log(`失敗:${reason}`);
  });

// 失敗:10

四、Promise 中其它經常使用方法

4.一、Promise.all

Promise.all(arr):返回的結果是一個 Promise 實例(all 實例),要求 arr 數組中的每一項都是一個新的 Promise 實例,Promise.all 是等待全部數組中的實例狀態都爲成功纔會讓「all 實例」狀態爲成功,Value 是一個集合,存儲着 arr 中每個實例返回的結果;凡是 arr 中有一個實例狀態爲失敗,「all 實例」的狀態也是失敗

let p1 = Promise.resolve(1);
let p2 = new Promise((resolve) => {
  setTimeout((_) => {
    resolve(2);
  }, 1000);
});
let p3 = Promise.reject(3);

Promise.all([p2, p1])
  .then((result) => {
    // 返回的結果是按照 arr 中編寫實例的順序組合在一塊兒的
    // [2,1]
    console.log(`成功:${result}`);
  })
  .catch((reason) => {
    console.log(`失敗:${reason}`);
  });

4.二、Promise.race

Promise.race(arr):和 all 不一樣的地方,race 是賽跑,也就是 arr 中無論哪個先處理完,處理完的結果做爲「race 實例」的結果

4.三、Promise.reject (選)

4.四、Promise.resolve (選)

let p1 = Promise.resolve(100);
let p2 = new Promise((resolve) => {
  setTimeout((_) => {
    resolve(200);
  }, 1000);
});
let p3 = Promise.reject(3);

// 1 2 100

五、async/await

ES7 中提供了 Promise 操做的語法糖:async / await

async function handle() {
  let result = await ajax1();
  result = await ajax2(result.map((item) => item.id));
  result = await ajax3();
  // 此處的result就是三次異步請求後獲取的信息
}
handle();

async 是讓一個普通函數返回的結果變爲 status=resolved 而且 value=return 結構的 Promise 實例

async 最主要的做用是配合 await 使用的,由於一旦在函數中使用 await,那麼當前的函數必須用 async 修飾

await 會等待當前 Promise 的返回結果,只有返回的狀態是 resolved 狀況,纔會把返回結果賦值給 result

await 不是同步編程,是異步編程(微任務):當代碼執行到此行(先把此行),構建一個異步的微任務(等待 Promise 返回結果,而且 Promise 下面的代碼也都被列到任務隊列中),

const p1 = () => new Promise();
const p2 = () => new Promise();

async function fn() {
  console.log(1);
  let result = await p2;
  console.log(result);

  let AA = await p1;
  console.log(AA);
}
fn();
console.log(2);

// 2
// 1
// p2 result
// p1 AA

若是 Promise 是失敗狀態,則 await 不會接收其返回結果,await 下面的代碼也不會在繼續執行( await 只能處理 Promise 爲成功狀態的時候)

const p3 = Promise.reject(10);
async function fn() {
  let reason = await p3;
  console.log(reason);
}
fn();

//

編輯時間:2020-08-18 21:15

相關文章
相關標籤/搜索