1.前言 在平時的業務開發中,前端通常需要請求後臺獲取數據,或者NodeJs讀取文件等等一系列的非同步操作,我們通常需要利用非同步操作的結果或者對非同步操作的結果進行處理。通常我們的解決方案是:在非同步操作成功或者失敗的回調函數裡面寫方法,在非同步操作比較簡單的時候這樣寫代碼還是比較好理解的,當業務逐漸趨於復 ...
1.前言
在平時的業務開發中,前端通常需要請求後臺獲取數據,或者NodeJs讀取文件等等一系列的非同步操作,我們通常需要利用非同步操作的結果或者對非同步操作的結果進行處理。通常我們的解決方案是:在非同步操作成功或者失敗的回調函數裡面寫方法,在非同步操作比較簡單的時候這樣寫代碼還是比較好理解的,當業務逐漸趨於複雜,這就形成了回調地獄,代碼嵌套層數太多並且難以理解。不過,辦法總是有的,可以使用ES6的新特性Promise來解決問題。
2.Promise的定義
Promise 是非同步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。
所謂Promise,簡單說就是一個容器,裡面保存著某個未來才會結束的事件(通常是一個非同步操作)的結果。從語法上說,Promise 是一個對象,從它可以獲取非同步操作的消息。Promise 提供統一的 API,各種非同步操作都可以用同樣的方法進行處理。
Promise對象有以下兩個特點。
(1)對象的狀態不受外界影響。Promise對象代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)。如果改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
有了Promise對象,就可以將非同步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的介面,使得控制非同步操作更加容易。
Promise也有一些缺點。首先,無法取消Promise,一旦新建它就會立即執行,無法中途取消。其次,如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
3.基本用法
ES6規定,Promise對象是一個構造函數,用來生成Promise實例
代碼如下:
const promise=new Promise(function(resolve,reject){ if(/* 非同步操作成功*/){ resolve(value) }else{ reject(error); } });
Promise構造函數接受一個函數作為參數,改函數的兩個參數分別是resolve與reject,resolve函數的作用是:將Promsie對象的狀態從“未完成”變為“成功”,在非同步操作成功時回調,並將非同步操作的結果value作為參數傳遞出去;reject函數的作用是:Promise對象的狀態由“未完成”變為“失敗”,在非同步操作失敗時調用,並將非同步操作報出的錯誤作為參數傳遞出去。
Promise實例生成以後,可以用then方法分別制定resolved的狀態和reject狀態的回調函數。
代碼如下:
promise.then(function(value) { // success }, function(error) { // failure });
4.小例子-封裝Ajax操作
const getJSON = function(url) { const promise = new Promise(function(resolve, reject){ const handler = function() { if (this.readyState !== 4) { return; } if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; const client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler; client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); }); return promise; }; getJSON("./js/package.json").then(function(json) { console.log('Contents: ' , json); }, function(error) { console.error('出錯了', error); });
以上的代碼是通過用原生的Ajax和Promise實現的獲取json的一個方法,在網頁中運行得出以下的結果:
5.reject狀態回調方法的寫法
promise .then(function(data) { // success }, function(err) { // error });
以上是我們的reject狀態方法,可以作為promsie對象then方法的第二個參數。不過這樣寫有個缺點是:如果在resolve狀態之後再拋出錯誤,則不會捕獲。
推薦寫法:
// 推薦寫法 promise .then(function(data) { //cb // success }) .catch(function(err) { // error });
通過Promise這種寫法,我們使很多非同步操作的方法寫法同步化,能夠更好的組織優化代碼,而且在捕獲錯誤也更加容易,方便我們調試解決問題。不足之處,多多指正。
參考資料: