![](http://static.javashuo.com/static/loading.gif)
Promise是一個構造函數,本身身上有all、reject、resolve這幾個眼熟的方法,原型上有then、catch等一樣很眼熟的方法。數組
var p = new Promise(function(resolve, reject){ //作一些異步操做 setTimeout(function(){ console.log('執行完成'); resolve('隨便什麼數據'); }, 2000); });
Promise的構造函數接收一個參數,是函數,而且傳入兩個參數:resolve,reject,分別表示異步操做執行成功後的回調函數和異步操做執行失敗後的回調函數。其實這裏用「成功」和「失敗」來描述並不許確,按照標準來說,resolve是將Promise的狀態置爲fullfiled,reject是將Promise的狀態置爲rejected。不過在咱們開始階段能夠先這麼理解,後面再細究概念。dom
function runAsync(){ var p = new Promise(function(resolve, reject){ //作一些異步操做 setTimeout(function(){ console.log('執行完成'); resolve('隨便什麼數據'); }, 2000); }); return p; } runAsync()
runAsync().then(function(data){ console.log(data); //後面能夠用傳過來的數據作些其餘操做 //...... });
function runAsync(callback){ setTimeout(function(){ console.log('執行完成'); callback('隨便什麼數據'); }, 2000); } runAsync(function(data){ console.log(data); });
效果也是同樣的,還費勁用Promise幹嗎。那麼問題來了,有多層回調該怎麼辦?若是callback也是一個異步操做,並且執行完後也須要有相應的回調函數,該怎麼辦呢?總不能再定義一個callback2,而後給callback傳進去吧。而Promise的優點在於,能夠在then方法中繼續寫Promise對象並返回,而後繼續調用then來進行回調操做。異步
runAsync1() .then(function(data){ console.log(data); return runAsync2(); }) .then(function(data){ console.log(data); return runAsync3(); }) .then(function(data){ console.log(data); });
這樣可以按順序,每隔兩秒輸出每一個異步回調中的內容,在runAsync2中傳給resolve的數據,能在接下來的then方法中拿到。運行結果以下:函數
猜猜runAsync一、runAsync二、runAsync3這三個函數都是如何定義的?沒錯,就是下面這樣post
function runAsync1(){ var p = new Promise(function(resolve, reject){ //作一些異步操做 setTimeout(function(){ console.log('異步任務1執行完成'); resolve('隨便什麼數據1'); }, 1000); }); return p; } function runAsync2(){ var p = new Promise(function(resolve, reject){ //作一些異步操做 setTimeout(function(){ console.log('異步任務2執行完成'); resolve('隨便什麼數據2'); }, 2000); }); return p; } function runAsync3(){ var p = new Promise(function(resolve, reject){ //作一些異步操做 setTimeout(function(){ console.log('異步任務3執行完成'); resolve('隨便什麼數據3'); }, 2000); }); return p; }
在then方法中,你也能夠直接return數據而不是Promise對象,在後面的then中就能夠接收到數據了,好比咱們把上面的代碼修改爲這樣:spa
runAsync1() .then(function(data){ console.log(data); return runAsync2(); }) .then(function(data){ console.log(data); return '直接返回數據'; //這裏直接返回數據 }) .then(function(data){ console.log(data); });
那麼輸出就變成了這樣:3d
function getNumber(){ var p = new Promise(function(resolve, reject){ //作一些異步操做 setTimeout(function(){ var num = Math.ceil(Math.random()*10); //生成1-10的隨機數 if(num<=5){ resolve(num); } else{ reject('數字太大了'); } }, 2000); }); return p; } getNumber() .then( function(data){ console.log('resolved'); console.log(data); }, function(reason, data){ console.log('rejected'); console.log(reason); } );
getNumber() .then(function(data){ console.log('resolved'); console.log(data); }) .catch(function(reason){ console.log('rejected'); console.log(reason); });
效果和寫在then的第二個參數裏面同樣。不過它還有另一個做用:在執行resolve的回調(也就是上面then中的第一個參數)時,若是拋出異常了(代碼出錯了),那麼並不會報錯卡死js,而是會進到這個catch方法中。請看下面的代碼:code
getNumber() .then(function(data){ console.log('resolved'); console.log(data); console.log(somedata); //此處的somedata未定義 }) .catch(function(reason){ console.log('rejected'); console.log(reason); });
Promise .all([runAsync1(), runAsync2(), runAsync3()]) .then(function(results){ console.log(results); });
Promise .race([runAsync1(), runAsync2(), runAsync3()]) .then(function(results){ console.log(results); });
//請求某個圖片資源 function requestImg(){ var p = new Promise(function(resolve, reject){ var img = new Image(); img.onload = function(){ resolve(img); } img.src = 'xxxxxx'; }); return p; } //延時函數,用於給請求計時 function timeout(){ var p = new Promise(function(resolve, reject){ setTimeout(function(){ reject('圖片請求超時'); }, 5000); }); return p; } Promise .race([requestImg(), timeout()]) .then(function(results){ console.log(results); }) .catch(function(reason){ console.log(reason); });