Promise是一套解決編程中異步操作問題的方案。所謂Promise對象,其實就像一個容器,包裹著一個未來才會發(fā)生(或結(jié)束)的事件的結(jié)果榴芳。比如發(fā)請求嗡靡,請求發(fā)出去之后要等一段時間之后才能收到結(jié)果(即使這個時間很短,但總不是立刻就能收到響應(yīng)窟感;為方便理解讨彼,你也可以夸張一點想象,比如請求發(fā)出之后要幾天才能得到響應(yīng))柿祈。
Promise對象的特點
1.對象的狀態(tài)不受外界影響哈误,只取決于異步操作的結(jié)果。Promise的狀態(tài)有三種:pending(進行中)谍夭、fulfilled(已成功,后面用resolved代替)和rejected(已失敽┠肌)紧索。Promise的狀態(tài)的改變?nèi)Q于異步操作的結(jié)果,如果異步操作是成功的菜谣,那么狀態(tài)由pending變成fulfilled珠漂,否則由pending變成rejected.
2.一旦狀態(tài)改變,就不會再變尾膊,任何時候都可以得到這個結(jié)果媳危。如果異步操作已經(jīng)成功了,那么它的狀態(tài)就變成了fulfilled,你任何時候傳入回調(diào)函數(shù)冈敛,它都只會執(zhí)行“成功的回調(diào)函數(shù)”待笑。
3.Promise對象一旦新建就會立即執(zhí)行。
缺點:如果不設(shè)置回調(diào)函數(shù)抓谴,promise拋出錯誤信息不會傳到外部暮蹂,只是內(nèi)部自己知道。
resolve()和reject()函數(shù)
//創(chuàng)建一個Promise實例,這里即promise
const promise= new Promise(function(resolve,reject){
if(/*異步操作成功*/)
resolve() //調(diào)用resolve癌压,將promise的狀態(tài)改為fulfilled仰泻,后面會根據(jù)這個狀態(tài)去調(diào)用相應(yīng)的回調(diào)函數(shù)
})else{
/*異步操作失敗*/
reject() //調(diào)用reject,將promise的狀態(tài)改為rejected滩届,后面會根據(jù)這個狀態(tài)去調(diào)用相應(yīng)的回調(diào)函數(shù)
}
文檔中有一段話很重要集侯,可以幫助你很好的理解resolve和reject函數(shù)的作用:
resolve函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved)帜消,在異步操作成功時調(diào)用棠枉,并將異步操作的結(jié)果,作為參數(shù)傳遞出去泡挺;reject函數(shù)的作用是术健,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected),在異步操作失敗時調(diào)用粘衬,并將異步操作報出的錯誤荞估,作為參數(shù)傳遞出去咳促。
從這段話我們可以總結(jié)出resolve和reject函數(shù)兩個重要的作用:
1.改變狀態(tài)
2.將異步操作的結(jié)果傳出去。異步操作的結(jié)果會作為resolve和reject的參數(shù)傳遞出去勘伺。
promise實例的then()方法
Promise實例生成后跪腹,有一個then()方法,這個方法接受2個參數(shù)飞醉,分別是promise對象狀態(tài)是resolved時調(diào)用的函數(shù)冲茸,和promise對象狀態(tài)是rejected時調(diào)用的函數(shù)。如果調(diào)用resolve函數(shù)和reject函數(shù)時帶有參數(shù)缅帘,那么它們的參數(shù)會被傳遞給回調(diào)函數(shù)轴术。
一般來說,調(diào)用resolve或reject以后钦无,Promise 的使命就完成了逗栽,后繼操作應(yīng)該放到then方法里面,而不應(yīng)該直接寫在resolve或reject的后面失暂。所以彼宠,最好在resolve()前面加上return語句,這樣就不會有意外弟塞。
幾個例子
- promise創(chuàng)建后立即執(zhí)行
let promise = new Promise(function(resolve, reject) {
console.log('Promise'); //創(chuàng)建后立即執(zhí)行凭峡,所以打印出‘Promise’
resolve();
});
promise.then(function() { //promise對象的回調(diào),會被推入到異步進程里决记,要等到所有同步腳本執(zhí)行完才會執(zhí)行
console.log('resolved.');
});
console.log('Hi!'); //在創(chuàng)建promise對象之后的同步腳本摧冀,打印出‘Hi’
// Promise
// Hi!
// resolved
Promise 新建后立即執(zhí)行,所以首先輸出的是Promise系宫。然后按价,then方法指定的回調(diào)函數(shù),將在當(dāng)前腳本所有同步任務(wù)執(zhí)行完才會執(zhí)行笙瑟,所以resolved最后輸出楼镐。
- 用Promise對象實現(xiàn)的 Ajax 操作的例子
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出錯了', error);
});
- resolve函數(shù)的參數(shù)可以是另外一個promise對象
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
// Error: fail
以上,p2 的reslove()方法將p1作為參數(shù)往枷。這時候框产,p2的狀態(tài)變成了由p1決定,如果p1的狀態(tài)是pending错洁,那么p2的回調(diào)函數(shù)就會等待p1的狀態(tài)改變秉宿;如果p1的狀態(tài)已經(jīng)是resolved或者rejected,那么p2的回調(diào)函數(shù)將會立刻執(zhí)行屯碴。
上面代碼中描睦,p1是一個 Promise,3 秒之后變?yōu)閞ejected导而。p2的狀態(tài)在 1 秒之后改變忱叭,resolve方法返回的是p1隔崎。由于p2返回的是另一個 Promise,導(dǎo)致p2自己的狀態(tài)無效了韵丑,由p1的狀態(tài)決定p2的狀態(tài)爵卒。所以,后面的then語句都變成針對后者(p1)撵彻。又過了 2 秒钓株,p1變?yōu)閞ejected,導(dǎo)致觸發(fā)catch方法指定的回調(diào)函數(shù)陌僵。