Promise是抽象異步處理對象以及對其進行各類操做的組件javascript
簡言之,使用Promise就是將javascript中異步的方式變換成同步來操做。Promise則是把相似的異步處理對象和處理規則進行規範化, 並按照採用統一的接口來編寫,規定方法以外的寫法都會報錯。簡單的示例:java
var promise = getAsyncPromise("fileA.txt"); //處於Pending狀態,既不是resolve也不是reject的狀態。是promise對象剛被建立後的初始化狀態 promise.then(function(result){ // 獲取文件內容成功時的處理 成功時狀態爲onFulfilled }).catch(function(error){ // 獲取文件內容失敗時的處理 失敗時狀態爲onRejected });
其中,then
和catch
表明函數執行成功和失敗的預設操做git
new
關鍵字var promise = new Promise(function(resolve, reject) { // 異步處理 // 處理結束後、調用resolve 或 reject });
then
promise.then(onFulfilled, onRejected); //onFulfilled函數會在promise對象的revolve狀態調用,onRejected爲在promise對象reject狀態下調用 promise.catch(function());//catch用來代替onRejected拋出錯誤
如Promise.all()
, Promise.race
,Promise.resolve()
,Promise.reject
等github
function getURL(URL) { return new Promise(function (resolve, reject) { var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function () { if (req.status === 200) { resolve(req.responseText);//傳入resolve中的參數會在狀態改變的時候,傳到then中 } else { reject(new Error(req.statusText)); } }; req.onerror = function () { reject(new Error(req.statusText)); }; req.send(); }); } // 運行示例 var URL = "http://httpbin.org/get"; getURL(URL).then(function onFulfilled(value){ console.log(value); }).catch(function onRejected(error){ console.error(error); });
Promise.resolve
做用1. Promise.resolve 是 new Promise(func)的快捷方式,如Promise.resolve(42);
與 new Promise(function(resolve){ resolve(42);});
做用2. 將thenable
對象轉換爲promise對象。thenable
指的是一個具備 .then
方法的對象。json
Promise.reject
Promise.reject(new Error("出錯了"))
等價於數組
new Promise(function(resolve,reject){ reject(new Error("出錯了")); });
使用promise
Promise.reject(new Error("BOOM!")).catch(function(error){ console.error(error); });
var promise = new Promise(function (resolve){ console.log("inner promise"); // 1 resolve(42); }); promise.then(function(value){ console.log(value); // 3 }); console.log("outer promise"); // 2
輸出結果爲 1,2,3; 即便resolve當即執行,得出的結果也在下一個時間環裏,須要等到下一週期才能執行異步
1.絕對不能對異步回調函數(即便在數據已經就緒)進行同步調用。
2.若是對異步回調函數進行同步調用的話,處理順序可能會與預期不符,可能帶來意料以外的後果。
3.對異步回調函數進行同步調用,還可能致使棧溢出或異常處理錯亂等問題。
4.若是想在未來某時刻調用異步回調函數的話,可使用setTimeout
等異步API。函數
對比三段代碼:this
第一段:直接判斷文件是否加載完成
function onReady(fn) { var readyState = document.readyState; if (readyState === 'interactive' || readyState === 'complete') { fn(); } else { window.addEventListener('DOMContentLoaded', fn); } } onReady(function () { console.log('DOM fully loaded and parsed'); }); console.log('==Starting==');
第二段:使用setTimeout轉同步爲異步操做
function onReady(fn) { var readyState = document.readyState; if (readyState === 'interactive' || readyState === 'complete') { setTimeout(fn, 0); //使用setTimeout轉化同步函數爲異步函數 } else { window.addEventListener('DOMContentLoaded', fn); } } onReady(function () { console.log('DOM fully loaded and parsed'); }); console.log('==Starting==');
第三段:使用promise的resolve將統一爲異步的方式,減小判斷
function onReadyPromise() { return new Promise(function (resolve, reject) { var readyState = document.readyState; if (readyState === 'interactive' || readyState === 'complete') { resolve(); } else { window.addEventListener('DOMContentLoaded', resolve); } }); } onReadyPromise().then(function () { console.log('DOM fully loaded and parsed'); }); console.log('==Starting==');
關於傳遞參數promise的寫法
function doubleUp(value) { return value * 2; } function increment(value) { return value + 1; } function output(value) { console.log(value);// => (1 + 1) * 2 } var promise = Promise.resolve(1);//構造一個返回參數爲1的promise對象 promise .then(increment) //此時increment函數中傳的vaule值爲1 .then(doubleUp) //此時doubleUp函數中傳的vaule值爲2 .then(output) //此時doubleUp函數中傳的vaule值爲 4 .catch(function(error){ // promise chain中出現異常的時候會被調用 console.error(error); });
Promise.resolve
和Promise.reject
會對函數中return返回的值進行包裝,最終then
返回的結果都是新建立的promise
對象
Promise.all
的使用
function getURL(URL) { return new Promise(function (resolve, reject) { var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function () { if (req.status === 200) { resolve(req.responseText); } else { reject(new Error(req.statusText)); } }; req.onerror = function () { reject(new Error(req.statusText)); }; req.send(); }); } var request = { comment: function getComment() { return getURL('http://azu.github.io/promises-book/json/comment.json').then(JSON.parse); }, people: function getPeople() { return getURL('http://azu.github.io/promises-book/json/people.json').then(JSON.parse); } }; function main() { return Promise.all([request.comment(), request.people()]); } // 運行示例 main().then(function (value) { console.log(value); }).catch(function(error){ console.log(error); });
證實Promise.all
的promise數組是同時開始執行的
// `delay`毫秒後執行resolve function timerPromisefy(delay) { return new Promise(function (resolve) { setTimeout(function () { resolve(delay); }, delay); }); } var startDate = Date.now(); // 全部promise變爲resolve後程序退出 Promise.all([ timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128) ]).then(function (values) { console.log(Date.now() - startDate + 'ms'); // 約128ms console.log(values); // [1,32,64,128] });
Promise.race
只要有一個promise對象進入 FulFilled 或者 Rejected 狀態的話,就會繼續進行後面的處理
// `delay`毫秒後執行resolve function timerPromisefy(delay) { return new Promise(function (resolve) { setTimeout(function () { resolve(delay); }, delay); }); } // 任何一個promise變爲resolve或reject 的話程序就中止運行 Promise.race([ timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128) ]).then(function (value) { console.log(value); // => 1 }); //代碼第二段 var winnerPromise = new Promise(function (resolve) { setTimeout(function () { console.log('this is winner'); resolve('this is winner'); }, 4); }); var loserPromise = new Promise(function (resolve) { setTimeout(function () { console.log('this is loser'); resolve('this is loser'); }, 1000); }); // 第一個promise變爲resolve後程序中止 Promise.race([winnerPromise, loserPromise]).then(function (value) { console.log(value); // => 'this is winner' });
不能進行錯誤處理的onRejected
function throwError(value) { // 拋出異常 throw new Error(value); } // <1> onRejected不會被調用 function badMain(onRejected) { return Promise.resolve(42).then(throwError, onRejected); } // <2> 有異常發生時onRejected會被調用 function goodMain(onRejected) { return Promise.resolve(42).then(throwError).catch(onRejected); } // 運行示例 badMain(function(){ console.log("BAD"); }); goodMain(function(){ console.log("GOOD"); });
說明:上面代碼中<1>中throwError 拋出了異常,onRejected 指定的函數也不會被調用
.then 和 .catch 都會建立並返回一個 新的 promise對象。 Promise實際上每次在方法鏈中增長一次處理的時候所操做的都不是徹底相同的promise對象。