Promise知識梳理

Promise是什麼?

通俗來說,Promise就是一個用於保存異步操做的容器。當一個異步操做完成後,它要麼保存了值,要麼保保存了錯誤的信息。Promise基本上就是「承諾」你它會給你一個異步操做的結果。git

這個對象分爲三個階段:數據庫

  • pending階段,建立promise對象時,處於掛起狀態,關聯某個異步操做。
  • Fullfilled階段,表示promise有結果將被履行,異步操做成功完成,有結果了。
  • Rejected階段,表示異步操做過程當中出現問題,被拒絕了,獲得錯誤值。

首先建立一個Promise對象,這個構造函數須要一個參數,這個參數是一個須要兩個參數的函數。分別是resolvereject兩個參數的匿名函數編程

const p = new Promise((resolve,reject) => {
    //成功後執行的函數
    resolve('hello')
    //失敗後執行的函數
    reject(new Error('message'))
}) 
複製代碼

咱們日常查詢一個數據庫,請求一個網絡服務或者設置一個延時執行的程序都會用到異步操做,而promise對象也就很是適合這些場合使用。數組

由於使用了promise,因此後面必定會給咱們一個異步操做的結果,不管是成功的函數失敗的。因此咱們須要將值返回給promise的使用者,咱們就用上面的resolvereject參數來實現。promise

假設上面的異步操做完成了,執行的結果就是「hello」。在現實編程中,這個「hello」也能夠是一個從數據庫中讀取的信息,這就是異步操做的結果。如今咱們須要兌現了,由於後續可能使用了p對象。看它有兩個方法。 bash

catch用於獲取任何的報錯, then用來獲取異步操做成功的返回值,咱們調用 then,而後傳入一個函數。這裏咱們傳入 result,就是裏面的 resolve函數。

const p = new Promise((resolve, reject) => {
  //成功後執行的函數
  resolve("hello");
  //失敗後執行的函數
  reject(new Error("message"));
});

p.then(result => console.log("result", result));
複製代碼

打開控制檯,運行promise.js網絡

咱們獲得告終果: hello,很好,再次改造下添加一個定時器,實現異步操做。

const p = new Promise((resolve, reject) => {
  //成功後執行的函數
  setTimeout(() => resolve("hello"), 2000);
  //失敗後執行的函數
  // reject(new Error("message"));
});

p.then(result => console.log("result", result));
複製代碼

再次運行,能夠看到間隔2秒後返回告終果。 異步

固然咱們也提到,若是有錯誤了,那麼將會把 error返回給調用者,最後連接上 catch,當遇到什麼問題的時候能夠了解到具體的錯誤是什麼。

const p = new Promise((resolve, reject) => {
  //成功後執行的函數
  setTimeout(() => {
    // resolve("hello");
    reject(new Error("message"));
  }, 2000);
});

p.then(result => console.log("result", result)).catch(err =>
  console.log("Error", err.message)
);
複製代碼

此次咱們再運行程序,將會獲得錯誤信息,由於咱們「拒絕」履行承諾。

如今總結一下,Promise是一個對象,用於保存異步操做的任何結果,當咱們建立對象的時候進入了掛起的狀態。上面的代碼就是它開始處理一個異步操做,這個操做有可能成功也可能失敗。async

若是成功了,咱們就說承諾「解決」了,或者是被履行了。Promise的狀態由掛起轉爲解決或者履行,咱們就用resolve函數返回結果給調用者。函數

若是異步操做失敗了,Promise的狀態由掛起轉爲拒絕,咱們就用reject函數返回一個錯誤給調用者。

這就是如何建立一個Promise,而後是如何使用它。咱們使用then來獲得結果,catch來捕捉錯誤對象。有一點須要提到的是若是在任何地方用到了異步的回調,都應該讓函數返回一個Promise

Promise並行操做是什麼?

有時咱們可能想要並行的處理幾個異步請求,當它們所有結束後再作點什麼。好比可能同時請求兩個或以上網站的API,當全部的請求都完畢的時候就能夠返回什麼給客戶端了。

首先建立兩個Promise對象,這裏咱們須要返回結果,不要被拒絕,因此就一個參數。

const p1 = new Promise(resolve => {
  setTimeout(() => {
    console.log("異步操做1");
    resolve(1);
  }, 2000);
});

const p2 = new Promise(resolve => {
  setTimeout(() => {
    console.log("異步操做2");
    resolve(2);
  }, 2000);
});
複製代碼

如今我想同時處理這兩個請求,當它們都完成的時候咱們再作些什麼。這裏調用Promise.all(),這是另外一個Promise類的靜態方法,而不是Promise對象的實例方法。而後傳入一個Promise對象的數組,這裏是p1p2,將會返回一個新的Promise。它的履行取決於全部包含Promise對象所有履行。先調用這個Promise,而後調用then,將結果顯示在控制檯。

Promise.all([p1, p2]).then(result => console.log(result));
複製代碼

能夠看到兩個都執行了,獲得了兩個結果組成的數組。

若是其中一個Promise對象失敗了呢?咱們修改第一個Promise,讓它有reject參數

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("異步操做1");
    reject(new Error("出現錯誤了"));
  }, 2000);
});

const p2 = new Promise(resolve => {
  setTimeout(() => {
    console.log("異步操做2");
    resolve(2);
  }, 2000);
});

Promise.all([p1, p2])
  .then(result => console.log(result))
  .catch(err => console.log("Error", err.message));
複製代碼

再次運行查看,只要其中一個Promise出錯了,所有Promise的最終返回值都會被拒絕。

若是隻要其中有 Promise實現了就當即進行某些操做,而不是等到全部所有履行。這樣的話可使用 race方法取代 all

const p1 = new Promise(resolve => {
  setTimeout(() => {
    console.log("異步操做1");
    resolve(1);
  }, 2000);
});

const p2 = new Promise(resolve => {
  setTimeout(() => {
    console.log("異步操做2");
    resolve(2);
  }, 2000);
});

Promise.race([p1, p2])
  .then(result => console.log(result))
  .catch(err => console.log("Error", err.message));
複製代碼

這樣只要其中一個 Promise履行,就能夠拿到結果。

Async/Await是什麼?

在如今的JavaScript中有個新特性,asyncawait,這可讓你寫同步代碼同樣寫異步代碼。

function getUser(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("讀取id中...");
      resolve({
        id: id,
        gitHubUsername: "mosh"
      });
    }, 2000);
  });
}

function getRepositories(username) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("獲取用戶信息中...");
      resolve(["repo1", "repo2", "repo3"]);
    }, 2000);
  });
}

function getCommits(text) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("獲取內容中...");
      resolve(["hello"]);
    }, 2000);
  });
}
複製代碼

要注意的是使用Async/Await,在Promise中咱們使用try-catch塊來捕捉異常,它沒有catch方法。在這個函數中,咱們將全部的異步操做代碼包含到try塊中,而後是catch塊。捕捉到的是err對象。若是有異常,catch塊的代碼就執行。

async function displayCommits() {
  try {
    const user = await getUser(1);
    const repos = await getRepositories(user.gitHubUsername);
    const commits = await getCommits(repos[0]);
    console.log(commits);
  } catch (err) {
    console.log("Error", err.message);
  }
}
displayCommits();
複製代碼

仍是在控制檯執行:

相關文章
相關標籤/搜索