promise 是什么
Promise 對象用于一個異步操作的最終完成(或失敗)及其結果值的表示。(簡單說就是處理異步請求。一個諾言,一個成功,一個失敗。)
看個例子
var promise = new Promise(function(resolve){
resolve(42);
});
promise.then(function(value){
console.log(value);
}).catch(function(error){
console.error(error);
});
運行后,打印出42,為什么會是42呢?帶著這個疑惑繼續放下看
promise 狀態
一個Promise必須處在其中之一的狀態:pending, fulfilled 或 rejected.
pending 狀態:可以轉換到 fulfilled 或 rejected 狀態。
fulfilled 狀態:不能轉換成任何其它狀態;必須有一個值,且這個值不能被改變。
rejected 狀態:不能轉換成任何其它狀態;必須有一個值,且這個值不能被改變。
promise 對象
創建 promise 對象
1.new Promise(fn)
返回一個 promise 對象。
2.fn是個函數,fn有兩個參數
- resolve:處理結果成功的時候調用
resolve(處理結果值)
。 - reject:處理結果錯誤的時候調用
reject(Error對象)
。
then 方法
一個 Promise 必須提供一個 then 方法來獲取其值。
Promise 的 then 方法接受兩個參數:
promise.then(onFulfilled,onRejected)
1.onFulfilled 和 onRejected 都是函數,如果不是函數,則忽略之。
2.onFulfilled :resolve(成功)時調用 onFulfilled,必須在promise fulfilled后調用,且promise的value為其第一個參數,不能多次調用。
3.onRejected:reject(失敗)時調用 onRejected,必須在promise rejected后調用, 且promise的reason為其第一個參數,不能被多次調用。
.catch
只是 promise.then(undefined, onRejected)
的別名而已。
Promise.reject(new Error("BOOM!")).catch(function(error){
console.error(error); // Error: BOOM!
});
開始那個例子就變成簡單明了,relove(42) 成功是調用function(value){console.log(value)}
,所以打印出 42 。
對于一個 promise,它的 then 方法可以調用多次。
promise.then(onFulfilled,onRejected).then(onFulfilled,onRejected);
promise.then(onFulfilled,onRejected); promise.then(onFulfilled,onRejected);
then 必須返回一個 promise
promise2 = promise1.then(onFulfilled, onRejected);
創建 XHR 的promise 對象
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()
})
}
// 運行
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 只有在通過XHR取得結果狀態為200時才會調用 resolve 。而其他情況(取得失敗)時則會調用 reject 方法。
當調用成功時,打印出
{
"name":"jack",
"nationality":"china"
}
我們把 url 地址故意寫錯,調用失敗,將會報錯,顯示如下
Error: Not Found
Promise 是同步還是異步執行
再看個例子
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 是異步執行的。有個問題,為什么 setTimeout 模擬異步會比 promise 晚出現呢?
這就涉及到 microtask 和 macrotask 問題。簡單說,promise 排在了異步下批執行的第一梯隊,而setTimeout 則排在第二梯隊。
Promise API
Promise.all 接收一個 promise對象的數組作為參數,當這個數組里的所有promise對象全部變為resolve或reject狀態的時候,它才會去調用 .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 接收一個 promise對象的數組作為參數,只要有一個promise對象進入 FulFilled 或者 Rejected 狀態的話,就會繼續進行后面的處理。
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 更快,所以它失敗了
});