ES6之Promise學習

初識Promise

Promise對象是一個構造函數,其接受一個函數做爲參數,resolvereject爲這個函數的參數,函數內部通常爲異步執行的代碼,resolve做爲異步執行完成以後成功的回調,reject做爲異步執行拋錯的回調。Promise構造函數能夠理解爲執行異步的過程,其resolvereject爲執行異步調用結果的回調函數。javascript

流程圖

// 代碼1
var p = new Promise((resolve, reject) => {
  // 執行一系列的異步執行
  // some codes...
  if (true) {
    resolve("異步執行成功");
  } else {
    reject("異步執行拋錯");
  }
}); // fulfilled: 異步執行成功 ; 非fulfilled: 異步執行拋錯

Promise的異步處理

then和catch的使用

Promise構造函數返回一個異步執行以後的promise對象,該對象對異步的結果進一步處理。java

// 代碼2
p
  .then((res) => {
    // try catch 手動拋錯
    try {
      // console.log("異步返回成功狀態");
      throw Error("錯誤代碼");
    } catch(e) {
      console.log("執行catch");
      return Promise.reject(e);
    }
  })
  .catch((res) => {
    console.log(res); // 輸出上一個 then 中 catch 的 e
    return "這裏由錯誤信息過去的數據";
  })
  .then((res) => {
    console.log(res); // 若上一個catch執行,輸出:這裏由錯誤信息過去的數據
  })

以上代碼執行結果:node

# 結果1
執行catch
Error: 錯誤代碼
    at p.then (**/promise.js:77:10)
    at process._tickCallback (internal/process/next_tick.js:109:7)
    at Module.runMain (module.js:607:11)
    at run (bootstrap_node.js:423:7)
    at startup (bootstrap_node.js:147:9)
    at bootstrap_node.js:538:3
這裏由錯誤信息過去的數據

promise對象的鏈式調用

代碼2能夠看出,promise對象狀態爲resolve的時候,執行then方法,並且在不拋錯狀況下會持續執行鏈式調用的then方法,若then方法拋出異常或者拋出返回Promise.reject()方法,會轉到執行catch方法,若catch方法返回的不是Promise.reject()方法或者不拋出異常,則全部使用return返回的數據都會做爲參數傳給下一個then函數參數的參數,即代碼2中的最後一個then方法指定函數參數的res是上一個catchreturn的數據。es6

var p = new Promise((resolve, reject) => {
  resolve("ok");
});
p.then((msg) => {
  console.log(msg);
  return Promise.reject("then01拋錯");
}).catch((errMsg) => {
  console.warn(errMsg);
}).then(() => {
  console.log("then02再執行");
}).then(() => {
  console.log("then03再執行");
  return Promise.reject("then03拋錯");
}).catch((errMsg) => {
  console.warn(errMsg);
  return "catch02 return 給下一個then指定方法的值";
}).then((msg) => {
  console.log(msg);
});

運行結果以下:bootstrap

運行結果

這是由於then方法和catch方法返回的都是一個promise對象。then方法指定的回調函數拋出錯誤會被下一個catch方法捕獲,多個then方法執行也是如此。catch方法會捕獲上一個catch方法(若是有的話)以後拋錯的錯誤。promise

鏈式調用

換言之,不管是then方法仍是catch方法,返回的都是一個promise對象,其狀態取決於上一個方法指定的函數是否順利執行或者沒有返回Promise.reject()瀏覽器

Promise狀態

一旦Promise的狀態變爲resolved或者rejected,就會永久保持該狀態,不會再變。bash

var p = new Promise((resolve, reject) => {
  resolve("ok");
  throw new Error("wrong");
});
p.then((msg) => {
  console.log(msg);
}).catch((errMsg) => {
  console.warn(errMsg);
});

// ok

在Promise的參數函數中,因爲先判定了resolved狀態,因此在以後只會執行then函數,後面拋出的錯誤會等於沒拋出來。異步

另外,「事件循環」會對拋出的結果有影響。函數

var p = new Promise((resolve, reject) => {
  resolve("ok");
  setTimeout(() => {
    throw new Error("wrong");
  }, 0);
});
p.then((msg) => {
  console.log(msg);
}).catch((errMsg) => {
  console.warn(errMsg);
});

// ok

// 瀏覽器拋出的錯誤
// index.js:4 Uncaught Error: wrong
//    at setTimeout (index.js:4)
// setTimeout    @    index.js:4

在本輪「事件循環」中,promise對象p先執行,因此構造函數Promise的指定函數先輸出‘ok’;在進入到下一次的「事件循環」的時候,因爲Promise函數體已經執行完畢,故後面拋出的錯誤是在Promise函數體外拋出的,Promise函數體沒法捕獲到這個錯誤。

Promise.resolve()

Promise.resolve()接受一個參數,其返回一個promise對象的狀態會由於傳入的參數的不一樣而不一樣。

參數分別如下幾種狀況:

返回一個狀態爲resolved的promise對象,也就是下一步會執行then方法。

var p = Promise.resolve();

p.then((res) => {
  console.log("then");
}).catch((res) => {
  console.log("catch");
});

// then
  • thenable對象

var thenable = {
  then: function (resolve, reject) {
    console.log("當即執行thenable的then的方法" + Date.now());
    resolve("判定以後的信息");
  }
}

var p = Promise.resolve(thenable);

p.then((res) => {
  console.log(res);
});

// 當即執行thenable的then的方法1494485393447
// 判定以後的信息

// 至關於

var p = new Promise(function (resolve, reject) {
  console.log("當即執行thenable的then的方法" + Date.now());
  resolve("判定以後的信息");
});

p.then((res) => {
  console.log(res);
});

// 當即執行thenable的then的方法1494485454503
// 判定以後的信息

thenable對象做爲參數,在執行Promise.resolve(thenable)方法的時候,會當即執行thenable對象中的then方法,而且其返回的Promise對象的狀態取決於thenable對象的then方法執行的是resolve()仍是reject()。這種狀況下,就至關於Promise構造函數以thenable對象的then方法做爲參數,實例化一個Promise實例。

  • 一個非Promise對象,且不含有then方法的對象------非thenable對象

var p = Promise.resolve({
  a: 1
});
p.then((res) => {
  console.log(res);
});

// { a: 1 }

var p01 = Promise.resolve('Hello Promise!');
p01.then((res) => {
  console.log(res);
});

// Hello Promise!

這種狀況下,Promise.resolve()的狀態爲resolved,其接收的參數會做爲then方法指定函數的參數。

  • Promise對象

var p01 = new Promise((resolve, reject) => {
  reject('Throw some error! Come on! You bite me.');
});

var p = Promise.resolve(p01);

p.then((res) => {
  console.log("這是then方法");
}).catch((errMsg) => {
  console.log(errMsg);
});

// Throw some error! Come on! You bite me.

傳入的是一個Promise對象,Promise.resolve()返回的對象的狀態就是傳入的Promise對象的狀態。

Promise.reject()

Promise.reject(reason)方法一樣返回一個狀態爲rejectedPromise對象實例。值得注意的是,參數reason(Promise狀態rejected的緣由)不管是什麼值,都會傳給返回的Promise對象的catch方法指定的函數做爲參數。

var p = Promise.reject('Throw some error! Come on! You bite me.');

p.then((res) => {
  console.log("這是then方法");
}).catch((errMsg) => {
  console.log(errMsg);
});

// Throw some error! Come on! You bite me.

promise對象的使用場景——圖片加載

var imgPromise = function (url) {
  return new Promise((resolve, reject) => {
    var img = new Image();
    img.src = url;
    img.onload = resolve;
    img.onerror = reject;
  });
}
imgPromise("http://imgurl")
  .then((res) => {
    console.log("圖片加載完成");
  })
  .catch((res) => {
    console.log("圖片加載失敗");
  }):

參考文章

相關文章
相關標籤/搜索