ECMAscript 6 原生提供了 Promise 對象。
Promise 對象用來傳遞異步操作的消息,代表一個異步操作的最終完成或者失敗。
特點
1、對象的狀態(tài)不受外界影響。Promise 對象代表一個異步操作,有三種狀態(tài):
pending: 初始狀態(tài),不是成功或失敗狀態(tài)。
fulfilled: 意味著操作成功完成。
rejected: 意味著操作失敗。
只有異步操作的結(jié)果,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài)。這也是 Promise 這個名字的由來,它的英語意思就是「承諾」,表示其他手段無法改變。
2、一旦狀態(tài)改變,就不會再變,任何時候都可以得到這個結(jié)果。Promise 對象的狀態(tài)改變,只有兩種可能:從 Pending 變?yōu)?Resolved 和從 Pending 變?yōu)?Rejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會再變了,會一直保持這個結(jié)果。就算改變已經(jīng)發(fā)生了,你再對 Promise 對象添加回調(diào)函數(shù),也會立即得到這個結(jié)果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監(jiān)聽,是得不到結(jié)果的。
優(yōu)點:
有了 Promise 對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調(diào)函數(shù)。此外,Promise 對象提供統(tǒng)一的接口,使得控制異步操作更加容易。
缺點:
1.無法取消 Promise,一旦新建它就會立即執(zhí)行,無法中途取消。2.如果不設(shè)置回調(diào)函數(shù),Promise 內(nèi)部拋出的錯誤,不會反應(yīng)到外部。3.當處于 Pending 狀態(tài)時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
在過去,要想做多重的異步操作,會導致經(jīng)典的回調(diào)地獄?,F(xiàn)在,我們可以把回調(diào)綁定到返回的 Promise 上,形成一個 Promise 鏈:
var promise = new Promise(function(resolve, reject) {
// 異步處理
// 處理結(jié)束后、調(diào)用resolve 或 reject
});
//對于已經(jīng)實例化過的 promise 對象可以調(diào)用 promise.then() 方法
promise().then(function(result){
return doSomethingElse(result);
}).then(function(newResult){
return doThirdThing(newResult);
}).then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
//也可以用[箭頭函數(shù)表示
promise().then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
下面是用 Promise 對象實現(xiàn)的 Ajax 操作的例子
var ajax = function (token) {
return new Promise(function(resolve,reject){
var xhr = window.XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject('Microsoft.XMLHTTP');
var url = '';
var obj = {'accessToken':token}
var params = "request="+JSON.stringify(obj);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
var res = JSON.parse(xhr.responseText);
if (res.code == 0) {
resolve(res.response.userId)
}else {
reject(res.msg)
}
} else {
alert('error')
}
}
}
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', "application/x-www-form-urlencoded");
xhr.send(params);
})
},
ajax(token).then(function(res){
sessionStorage.setItem('userid',res);
}).catch(function(res){
console.log(res)
})
Promise.all方法,Promise.race方法,Promise.any方法
Promise.all和Promise.race是并行運行異步操作的兩個組合式工具。
Promise.all()
Promise.all 方法接收一個promise的iterable類型(注:Array,Map,Set都屬于ES6的iterable類型)的輸入,且返回的每個成員都是 Promise 實例,那個輸入的所有promise的resolve回調(diào)的結(jié)果是一個數(shù)組。
Promise 的狀態(tài)由promise1、promise2、promise3 決定,分成兩種情況。
(1)只有promise1、promise2、promise3的狀態(tài)都變成fulfilled,Promise 的狀態(tài)才會變成fulfilled,此時promise1、promise2、promise3的返回值組成一個數(shù)組,傳遞給p的回調(diào)函數(shù)。
(2)只要promise1、promise2、promise3之中有一個被rejected,Promise 的狀態(tài)就變成rejected,Promise.all 異步地將失敗的那個結(jié)果給失敗狀態(tài)的回調(diào)函數(shù),而不管其它 promise 是否完成
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
var p3 = Promise.all([1,2,3, Promise.reject(555)]);
//log
// Promise { <state>: "rejected", <reason>: 555 }
Promise.all 當且僅當傳入的可迭代對象為空時為同步:
var p = Promise.all([]); // will be immediately resolved
var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously
console.log(p);
console.log(p2)
setTimeout(function(){
console.log('the stack is now empty');
console.log(p2);
});
// logs
// Promise { <state>: "fulfilled", <value>: Array[0] }
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }
Promise.race()
Promise.race(iterable) 方法返回一個 promise,一旦迭代器中的某個promise解決或拒絕,返回的 promise就會解決或拒絕。
race 函數(shù)返回一個 Promise,它將與第一個傳遞的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失?。╮ejects),這要取決于第一個完成的方式是兩個中的哪個。
如果傳的迭代是空的,則返回的 promise 將永遠等待。
如果迭代包含一個或多個非承諾值和/或已解決/拒絕的承諾,則 Promise.race 將解析為迭代中找到的第一個值。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
Promise.any()
E12新增的Promise的方法
接收一個Promise數(shù)組,數(shù)組中如有非Promise項,則此項當做成功
如果有一個Promise成功,則返回這個成功結(jié)果
如果所有Promise都失敗,則報錯
var promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'one');
});
var promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, 'two');
});
var promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 50, 'three');
});
var promise4 = new Promise((resolve, reject) => {
setTimeout(reject, 50, 'four');
});
// 當有成功的時候,返回最快那個成功
Promise.any([promise1,promise2,promise3]).then((value) => {
console.log(value)//three
})
//當全都失敗時
Promise.any([promise2,promise4]).then((value) => {
console.log(value)
},err =>{
console.log(err)//AggregateError: All promises were rejected
})