關於Promise的總結
Promise是異步編程的一種“解決方案”,這裏說的是一種解決方案,就是為了解決我們傳統使用回調函數和事件來實現異步的復雜及不合理性。
從抽象上來說 Promise就是一個容器,裏面存儲了某個未來才會結束的事件(一個異步操作)的結果。
從語法上來說 Promise就是一個對象,從它我們可以獲取異步操作的各種消息。它提供了統一的API,各種異步操作都可以用同樣的方法來進行處理。
從上圖中我們看出來 Promise就是一個構造函數,自身有resolve,reject,all,race 等方法。原型上有then和catch方法, 也就是說所有Promise的實例都有then和catch方法。
首先來創建一個簡單的 Promise對象 promise,這裏我們使用定時器來模擬異步操作。
1 const promise = new Promise(function (resolve,reject) { 2 setTimeout(function () { 3 console.log(‘異步操作‘); 4 resolve(‘這是完成‘);
reject(‘這是失敗或者錯誤‘); 5 },1000);
6 });
Promise構造函數接受一個‘函數類‘參數,這個函數有兩個參數resolve和reject。
執行1秒之後返回———‘異步操作‘ ,並且調用resolve或者reject方法(這兩個方法根據異步操作結果成功或者失敗調用)。
也許可能對resolve和reject這兩個方法有點不理解,這兩個方法是幹嘛用的,什麽時候執行。在這之前先讓我們來看一下Promise的三個特點。
1、Promise對象的狀態是不受外界影響的,它代表一個異步操作,有三種狀態:Pending(進行中),Fulfilled(已成功)和Rejected(已失敗)。
>>resolve(成功)時會調用 onFulfilled,reject(失敗)時會調用
onRejected。
>>只有異步操作的結果可以決定當前是哪一種狀態(成功的結果我們去調用resolve,失敗的結果我們去調用reject)。
2、一旦狀態改變,就不會再變,任何時候都可以得到這個結果。
3、上述代碼中我們並沒有執行這個對象,只是new 了一個Promise對象。也就是說一旦建立它就會立即執行。所以一般我們會在外面包裹一個函數,控制它什麽時候執行。
function asyncFun() { const promise = new Promise(function (resolve, reject) { setTimeout(function () { console.log(‘異步操作‘); resolve(‘這是完成‘); reject(‘這是失敗或者錯誤‘); }, 1000); }); return promise; } //asyncFun.then(onFulfilled,onRejected); asyncFun().then(function (data) { console.log(data);//這是完成 },function (data) { console.log(data); });
上述代碼中我們在promise對象的外層包裝了一個函數asyncFun,返回promies對象。
對通過new生成的promise對象為了設置其結果在 resolve(成功) 或者 reject(失敗)時調用的回調函數,我們可以使用asyncFun().then()
實例方法。
asyncFun().then(onFulfilled, onRejected) resolve(成功)時onFulfilled會被調用,reject(失敗)時onRejected會被調用。
onFulfilled, onRejected為可選參數,如果只想處理錯誤的結果,可以asyncFun().then(undefined, onRejected)這樣使用,不過這種情況下建議使用另外一個方法:asyncFun().catch(onRejected)。
這時候你應該有所領悟了,原來then裏面的函數就跟我們平時的回調函數一個意思,能夠在asyncFun這個異步任務執行完成之後被執行,並且會拿到我們在asyncFun中調用resolve時傳的的參數。這就是Promise的作用了,簡單來講,就是能把原來的回調寫法分離出來,在異步操作執行完後,用鏈式調用的方式執行回調函數。
OK ,再來看成功或者失敗的例子。
function asyncFun() { const promise = new Promise(function (resolve, reject) { setTimeout(function () { let num = Math.ceil(Math.random()*10); if(num>=5){ console.log(‘resolve‘); resolve(num); }else{ console.log(‘reject‘); reject(‘數值小於5,失敗了‘); } }, 1000); }); return promise; } //asyncFun.then(onFulfilled,onRejected); asyncFun().then(function (data) { console.log(data); },function (data) { console.log(data); });
asyncFun函數用來異步獲取一個數值,如果這個這個值大於等於5,我們標識為‘成功’了,調用resolve方法改變Promise的狀態。否則為失敗,調用reject方法並傳一個失敗的參數,作為原因。
多次運行之後我們可能得到下面的執行結果:(resolve 6) 或者 (reject 4)
我們也可以把上面的reject回調改為catch(fn);如下:
asyncFun().then(function (data) { console.log(data); }).catch(function(data){ console.log(data); });
與上面的操作結果是一樣的。
最後我們再來看一下我們常見到的使用方式:Fn().then().then().then() ... .catch();鏈式調用方法。
我們還是使用上面的方法,多復制幾個。
function asyncFun() { const promise = new Promise(function (resolve, reject) { setTimeout(function () { console.log(‘異步操作‘);
resolve(‘resolve‘) }, 1000); }); return promise; } function asyncFun1() { const promise = new Promise(function (resolve, reject) { setTimeout(function () { console.log(‘異步操作1‘);
resolve(‘resolve1‘) }, 1000); }); return promise; } function asyncFun2() { const promise = new Promise(function (resolve, reject) { setTimeout(function () { console.log(‘異步操作2‘)
resolve(‘resolve2‘) }, 1000); }); return promise; } //asyncFun.then(onFulfilled,onRejected); asyncFun().then(function (data) { console.log(data); return asyncFun1(); }).then(function (data) { console.log(data); return asyncFun2(); }).then(function (data) { console.log(data); }).catch(function (data) { console.log(data); });
這樣我們就可以實現用同步的寫法,實現層層回調異步的解決方案。而且能夠根據上一個的操作狀態控制下一個異步操作執行。
這樣能夠按順序,每隔兩秒輸出每個異步回調中的內容,在asyncFun2中傳給resolve的數據,能在接下來的then方法中拿到。
在then方法中我們也可以直接return 一個結果。例如:
asyncFun().then(function (data) { console.log(data); return ‘操作結果‘; //操作結果 }).then(function (data) { console.log(data); return asyncFun2(); }).then(function (data) { console.log(data); }).catch(function (data) { console.log(data); });
另外一點要說的是,如果我們在then 返回或者執行了一行錯誤的代碼,也不會阻斷代碼的執行,而是會直接走到 catch()方法中。例如:
asyncFun().then(function (data) { console.log(data); console.log(abc); return ‘操作結果‘; //操作結果 }).then(function (data) { console.log(data); return asyncFun2(); }).then(function (data) { console.log(data); }).catch(function (data) { console.log(data); });
上面的abc變量未定義,但是沒有阻斷代碼的執行,而是在catch裏提示我們 abc is not defined。
關於Promise的總結