promise含義:es6
所謂Promise
,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。json
從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。數組
promise基本用法:promise
Promise
構造函數接受一個函數做爲參數,該函數的兩個參數分別是resolve
和reject
。它們是兩個函數,由 JavaScript 引擎提供,不用本身部署。 異步
resolve函數的做用是,將Promise對象的狀態從「未完成」變爲「成功」(即從 pending 變爲 resolved),在異步操做成功時調用,並將異步操做的結果,做爲參數傳遞出去;函數
reject函數的做用是,將Promise對象的狀態從「未完成」變爲「失敗」(即從 pending 變爲 rejected),在異步操做失敗時調用,並將異步操做報出的錯誤,做爲參數傳遞出去。post
Promise
實例生成之後,能夠用then
方法分別指定resolved
狀態和rejected
狀態的回調函數。fetch
const promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操做成功 */){ resolve(value); } else { reject(error); } }); promise.then(function(value) { // success }, function(error) { // failure });
promise新建後就會當即執行spa
var promise = new Promise(function(resolve, reject) { console.log('Promise instance'); resolve(); }); promise.then(function() { console.log('resolved result'); }); for(var i=0;i<100;i++) { console.log(i);
} /* Promise instance 1 2 3 ... 99 100 resolved result */
resolve
函數的參數除了正常的值之外,還多是另外一個 Promise 實例,好比像下面這樣。prototype
const p1 = new Promise(function (resolve, reject) { // ... }); const p2 = new Promise(function (resolve, reject) { // ... resolve(p1); })
上面代碼中,p1
和p2
都是 Promise 的實例,可是p2
的resolve
方法將p1
做爲參數,即一個異步操做的結果是返回另外一個異步操做。
注意,這時p1
的狀態就會傳遞給p2
,也就是說,p1
的狀態決定了p2
的狀態。若是p1
的狀態是pending
,那麼p2
的回調函數就會等待p1
的狀態改變;若是p1
的狀態已是resolved
或者rejected
,那麼p2
的回調函數將會馬上執行。
promise.prototype,then()
Promise 實例具備then
方法,也就是說,then
方法是定義在原型對象Promise.prototype
上的。它的做用是爲 Promise 實例添加狀態改變時的回調函數。
前面說過,then
方法的第一個參數是resolved
狀態的回調函數,第二個參數(可選)是rejected
狀態的回調函數。
then
方法返回的是一個新的Promise
實例(注意,不是原來那個Promise
實例)。所以能夠採用鏈式寫法,即then
方法後面再調用另外一個then
方法。
getJSON("/posts.json").then(function(json) { return json.post; }).then(function(post) { // ... });
上面的代碼使用then
方法,依次指定了兩個回調函數。第一個回調函數完成之後,會將返回結果做爲參數,傳入第二個回調函數。
採用鏈式的then
,能夠指定一組按照次序調用的回調函數。這時,前一個回調函數,有可能返回的仍是一個Promise
對象(即有異步操做),這時後一個回調函數,就會等待該Promise
對象的狀態發生變化,纔會被調用。
getJSON("/post/1.json").then(function(post) { return getJSON(post.commentURL); }).then(function (comments) { console.log("resolved: ", comments); }, function (err){ console.log("rejected: ", err); });
上面代碼中,第一個then
方法指定的回調函數,返回的是另外一個Promise
對象。這時,第二個then
方法指定的回調函數,就會等待這個新的Promise
對象狀態發生變化。若是變爲resolved
,就調用第一個回調函數,若是狀態變爲rejected
,就調用第二個回調函數。
若是採用箭頭函數,上面的代碼能夠寫得更簡潔。
getJSON("/post/1.json").then(
post => getJSON(post.commentURL) ).then(
comments => console.log("resolved: ", comments), err => console.log("rejected: ", err) );
promise.prototype.catch()
getJSON('/posts.json').then(function(posts) { // ... }).catch(function(error) {
// 處理 getJSON 和 前一個回調函數運行時發生的錯誤 console.log('發生錯誤!', error); });
上面代碼中,getJSON方法返回一個 Promise 對象,若是該對象狀態變爲resolved,則會調用then方法指定的回調函數;
若是異步操做拋出錯誤,狀態就會變爲rejected,就會調用catch方法指定的回調函數,處理這個錯誤。另外,then方法指定的回調函數,若是運行中拋出錯誤,也會被catch方法捕獲。
p.then((val) => console.log('fulfilled:', val)) .catch((err) => console.log('rejected', err)); // 等同於 p.then((val) => console.log('fulfilled:', val)) .then(null, (err) => console.log("rejected:", err));
通常來講,不要在then
方法裏面定義 Reject 狀態的回調函數(即then
的第二個參數),老是使用catch
方法。
// bad promise .then(function(data) { // success }, function(err) { // error }); // good promise .then(function(data) { //cb // success }) .catch(function(err) { // error });
上面代碼中,第二種寫法要好於第一種寫法,理由是第二種寫法能夠捕獲前面then
方法執行中的錯誤,也更接近同步的寫法(try/catch
)。所以,建議老是使用catch
方法,而不使用then
方法的第二個參數。
promise.protype.finally
finally
方法用於指定無論 Promise 對象最後狀態如何,都會執行的操做。該方法是 ES2018 引入標準的。
promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});
promise.all
Promise.all
方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。
const p = Promise.all([p1, p2, p3]);
上面代碼中,Promise.all
方法接受一個數組做爲參數,p1
、p2
、p3
都是 Promise 實例,若是不是,就會先調用下面講到的Promise.resolve
方法,將參數轉爲 Promise 實例,再進一步處理。(Promise.all
方法的參數能夠不是數組,但必須具備 Iterator 接口,且返回的每一個成員都是 Promise 實例。)
p
的狀態由p1
、p2
、p3
決定,分紅兩種狀況。
(1)只有p1
、p2
、p3
的狀態都變成fulfilled
,p
的狀態纔會變成fulfilled
,此時p1
、p2
、p3
的返回值組成一個數組,傳遞給p
的回調函數。
(2)只要p1
、p2
、p3
之中有一個被rejected
,p
的狀態就變成rejected
,此時第一個被reject
的實例的返回值,會傳遞給p
的回調函數。
promise.race()
Promise.race
方法一樣是將多個 Promise 實例,包裝成一個新的 Promise 實例。
const p = Promise.race([p1, p2, p3]);
上面代碼中,只要p1
、p2
、p3
之中有一個實例率先改變狀態,p
的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給p
的回調函數。
Promise.race
方法的參數與Promise.all
方法同樣,若是不是 Promise 實例,就會先調用下面講到的Promise.resolve
方法,將參數轉爲 Promise 實例,再進一步處理。
下面是一個例子,若是指定時間內沒有得到結果,就將 Promise 的狀態變爲reject
,不然變爲resolve
。
const p = Promise.race([ fetch('/resource-that-may-take-a-while'), new Promise(function (resolve, reject) { setTimeout(() => reject(new Error('request timeout')), 5000) }) ]); p .then(console.log) .catch(console.error);