promise 是什么
Promise 對(duì)象用于一個(gè)異步操作的最終完成(或失斂纸酢)及其結(jié)果值的表示往果。(簡(jiǎn)單說(shuō)就是處理異步請(qǐng)求。一個(gè)諾言一铅,一個(gè)成功陕贮,一個(gè)失敗。)
看個(gè)例子
var promise = new Promise(function(resolve){
resolve(42);
});
promise.then(function(value){
console.log(value);
}).catch(function(error){
console.error(error);
});
運(yùn)行后潘飘,打印出42肮之,為什么會(huì)是42呢?帶著這個(gè)疑惑繼續(xù)放下看
promise 狀態(tài)
一個(gè)Promise必須處在其中之一的狀態(tài):pending, fulfilled 或 rejected.
pending 狀態(tài):可以轉(zhuǎn)換到 fulfilled 或 rejected 狀態(tài)福也。
fulfilled 狀態(tài):不能轉(zhuǎn)換成任何其它狀態(tài)局骤;必須有一個(gè)值,且這個(gè)值不能被改變暴凑。
rejected 狀態(tài):不能轉(zhuǎn)換成任何其它狀態(tài)峦甩;必須有一個(gè)值,且這個(gè)值不能被改變现喳。
promise 對(duì)象
創(chuàng)建 promise 對(duì)象
1.new Promise(fn)
返回一個(gè) promise 對(duì)象凯傲。
2.fn是個(gè)函數(shù),fn有兩個(gè)參數(shù)
- resolve:處理結(jié)果成功的時(shí)候調(diào)用
resolve(處理結(jié)果值)
嗦篱。 - reject:處理結(jié)果錯(cuò)誤的時(shí)候調(diào)用
reject(Error對(duì)象)
冰单。
then 方法
一個(gè) Promise 必須提供一個(gè) then 方法來(lái)獲取其值。
Promise 的 then 方法接受兩個(gè)參數(shù):
promise.then(onFulfilled,onRejected)
1.onFulfilled 和 onRejected 都是函數(shù)灸促,如果不是函數(shù)诫欠,則忽略之涵卵。
2.onFulfilled :resolve(成功)時(shí)調(diào)用 onFulfilled,必須在promise fulfilled后調(diào)用荒叼,且promise的value為其第一個(gè)參數(shù)轿偎,不能多次調(diào)用。
3.onRejected:reject(失敗)時(shí)調(diào)用 onRejected被廓,必須在promise rejected后調(diào)用坏晦, 且promise的reason為其第一個(gè)參數(shù),不能被多次調(diào)用嫁乘。
.catch
只是 promise.then(undefined, onRejected)
的別名而已昆婿。
Promise.reject(new Error("BOOM!")).catch(function(error){
console.error(error); // Error: BOOM!
});
開始那個(gè)例子就變成簡(jiǎn)單明了,relove(42) 成功是調(diào)用function(value){console.log(value)}
蜓斧,所以打印出 42 仓蛆。
對(duì)于一個(gè) promise,它的 then 方法可以調(diào)用多次挎春。
promise.then(onFulfilled,onRejected).then(onFulfilled,onRejected);
promise.then(onFulfilled,onRejected); promise.then(onFulfilled,onRejected);
then 必須返回一個(gè) promise
promise2 = promise1.then(onFulfilled, onRejected);
創(chuàng)建 XHR 的promise 對(duì)象
function ajax(options){
return new Promise(function(resolve,reject){
let {method,url} = options;
let xhr = new XMLHttpRequest();
xhr.open(method,url);
xhr.onload = function(){
if(xhr.status === 200){
resolve(xhr.responseText)
}else{
reject(new Error(xhr.statusText))
}
};
xhr.onerror = function(){
reject(new Error(xhr.statusText))
};
xhr.send()
})
}
// 運(yùn)行
var promise = ajax({method:'GET',url:'xxx.json'});
promise.then(function(value){
console.log(value)
},function(reason){
console.error(reason)
})
// xxx.json
{
"name":"jack",
"nationality":"china"
}
ajax 只有在通過(guò)XHR取得結(jié)果狀態(tài)為200時(shí)才會(huì)調(diào)用 resolve 多律。而其他情況(取得失敗)時(shí)則會(huì)調(diào)用 reject 方法搂蜓。
當(dāng)調(diào)用成功時(shí),打印出
{
"name":"jack",
"nationality":"china"
}
我們把 url 地址故意寫錯(cuò)辽装,調(diào)用失敗帮碰,將會(huì)報(bào)錯(cuò),顯示如下
Error: Not Found
Promise 是同步還是異步執(zhí)行
再看個(gè)例子
console.log(1)
setTimeout(function(){
console.log(2)
},0)
var promise =new Promise(function(resolve){
resolve(3)
}).then(function(value){
console.log(value)
})
console.log(4)
打印出1 4 3 2拾积。
Promise 是異步執(zhí)行的殉挽。有個(gè)問題,為什么 setTimeout 模擬異步會(huì)比 promise 晚出現(xiàn)呢?
這就涉及到 microtask 和 macrotask 問題拓巧。簡(jiǎn)單說(shuō)斯碌,promise 排在了異步下批執(zhí)行的第一梯隊(duì),而setTimeout 則排在第二梯隊(duì)肛度。
Promise API
Promise.all 接收一個(gè) promise對(duì)象的數(shù)組作為參數(shù)傻唾,當(dāng)這個(gè)數(shù)組里的所有promise對(duì)象全部變?yōu)閞esolve或reject狀態(tài)的時(shí)候,它才會(huì)去調(diào)用 .then 方法承耿。
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise(function(resolve) {
setTimeout(resolve, 500, "foo");
});
Promise.all([p1, p2, p3]).then(function(value) {
console.log(value); // [3, 1337, "foo"]
});
Promise.race 接收一個(gè) promise對(duì)象的數(shù)組作為參數(shù)冠骄,只要有一個(gè)promise對(duì)象進(jìn)入 FulFilled 或者 Rejected 狀態(tài)的話,就會(huì)繼續(xù)進(jìn)行后面的處理加袋。
var p5 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "five");
});
var p6 = new Promise(function(resolve, reject) {
setTimeout(reject, 100, "six");
});
Promise.race([p5, p6]).then(function(value) {
console.log(value)
}, function(reason) {
console.log(reason); // "six"
// p6 更快凛辣,所以它失敗了
});