ES6中的 Promise 是異步編程的一種解決方案。Promise是一個對象,從Promise中,可以獲取異步操作的消息從而對異步操作進行響應。Promise可以將異步操作以同步操作的流程表現出來,避免了嵌套回調函數可能出現的問題。不過Promise也存在着一定的問題,例如Promise是無法中途取消的,並且如果不設置回調函數,或者使用catch方法,那麼Promise內部出現的錯誤是不會被反應出來的。
Promise對象主要有三種描述狀態,Pending(進行中),Resolved(已完成)和Rejected(已經失敗)。Promise對象的狀態不受外界的影響,異步操作的結果決定了Promise處於何種狀態。並且一旦Promise的狀態發生改變,那麼任何操作都無法再改變它。
var promise = new Promise(function(resolve,reject){
});
promise.then(function(success){
/*
* code
*/
},function(error){
/*
*code
*/
});
從上面的例子中,我們可以看到,Promise構造函數接受了一個函數作爲參數。該函數帶有兩個參數,resolve和reject。這兩個參數同樣也是函數,resolve函數的作用用來在異步操作成功時,將成功的結果作爲參數傳遞出去給then方法。reject函數的作用用來在異步操作失敗時,將失敗的結果作爲參數傳遞出去。而then方法則接受兩個函數作爲參數,其中第一個參數是必須的,第二個參數則可以省略。
下面我們來看一個例子。
var getJSON = function(requestUrl){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest();
xhr.open("GET",requestUrl);
xhr.responseType = "json";
xhr.setRequestHeader("Accept", "application/json");
xhr.onreadystatechange = callback;
xhr.send();
function callback(){
if (this.readyState !== 4) {
return false;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
});
}
var url = "http://campus.iot.xiaofuonline.com:8090/......;
getJSON(url).then(function(response){
console.log("response = " + JSON.stringify(response));
},function(error){
console.log("error = " + error);
});
在上面的例子中,我們封裝了一個http請求。當請求成功時,調用resolve函數,請求失敗時,調用reject函數,兩個函數都帶有對應的參數,這兩個參數都會被傳遞給對應的回調函數。
當然我們並不建議說在then方法中去捕獲錯誤,比如我們嵌套了兩個異步操作的話。
getJSON(url).then(function(response){
console.log(JSON.stringify(response));
return getJSON(url);
},function(error){
console.log(error);
}).then(function(res){
console.log(JSON.stringify(res));
},function(error){
console.log(error);
});
這樣將變得異常麻煩,好在Promise爲我們提供了一個catch方法。上述中嵌套的任何一個異步操作拋出的錯誤都將會被catch最後捕獲。
舉個例子 爲了方便 下面用到了箭頭函數。
var err = function(){
return new Promise((resolve,reject) => {
reject('error');
});
}
getJSON(url).then((response) => {
console.log('success');
return err();
}).catch((error) => {
console.log(error);
});
Promise 還提供了幾個比較常用的方法,比如all()方法。all方法只有在所有的promise實例的狀態都變爲resolve後纔會觸發resolve函數,只要有任何一個的狀態是reject的,那麼就會立刻觸發reject函數。
var p = [1000,2000,3000].map((ms)=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(ms);
resolve();
},ms);
});
});
Promise.all(p).then(()=>{
console.log("success ==");
}).catch(()=>{
console.log('error');
});
今天之所以提到了Promise,主要是爲了後面jQuery源碼Deferred模塊提供一些基礎知識。