最近在開發中遇到一個問題:Table行內有下拉組件四級聯動,並且還能夠添加新行,每一個新行又是四級聯動,問:如何解決?想了半天因而使用Promise解決,讓我從新對Promise有了認識。javascript
經過MDN 官方文檔對Promise有段介紹:Promise 對象用於表示一個異步操做的最終完成 (或失敗)及其結果值。html
一個 Promise 對象表明一個在這個 promise 被建立出來時不必定已知的值。它讓您可以把異步操做最終的成功返回值或者失敗緣由和相應的處理程序關聯起來。 這樣使得異步方法能夠像同步方法那樣返回值:異步方法並不會當即返回最終的值,而是會返回一個 promise,以便在將來某個時候把值交給使用者。java
一個 Promise 必然處於如下幾種狀態之一:ios
待定狀態的 Promise 對象要麼會經過一個值被兌現(fulfilled),要麼會經過一個緣由(錯誤)被拒絕(rejected)。當這些狀況之一發生時,咱們用 promise 的 then 方法排列起來的相關處理程序就會被調用。若是 promise 在一個相應的處理程序被綁定時就已經被兌現或被拒絕了,那麼這個處理程序就會被調用,所以在完成異步操做和綁定處理方法之間不會存在競爭狀態。es6
由於 Promise.prototype.then 和 Promise.prototype.catch 方法返回的是 promise, 因此它們能夠被鏈式調用。axios
一、構造函數segmentfault
Promise()
建立一個新的 Promise 對象。該構造函數主要用於包裝尚未添加 promise 支持的函數。api
二、靜態方法數組
Promise.all(iterable)
這個方法返回一個新的promise對象,該promise對象在iterable參數對象裏全部的promise對象都成功的時候纔會觸發成功,一旦有任何一個iterable裏面的promise對象失敗則當即觸發該promise對象的失敗。這個新的promise對象在觸發成功狀態之後,會把一個包含iterable裏全部promise返回值的數組做爲成功回調的返回值,順序跟iterable的順序保持一致;若是這個新的promise對象觸發了失敗狀態,它會把iterable裏第一個觸發失敗的promise對象的錯誤信息做爲它的失敗錯誤信息。Promise.all方法常被用於處理多個promise對象的狀態集合。(能夠參考jQuery.when方法---譯者注)promise
Promise.allSettled(iterable)
等到全部promises都已敲定(settled)(每一個promise都已兌現(fulfilled)或已拒絕(rejected))。
返回一個promise,該promise在全部promise完成後完成。並帶有一個對象數組,每一個對象對應每一個promise的結果。
Promise.any(iterable)
接收一個Promise對象的集合,當其中的一個 promise 成功,就返回那個成功的promise的值。
Promise.race(iterable)
當iterable參數裏的任意一個子promise被成功或失敗後,父promise立刻也會用子promise的成功返回值或失敗詳情做爲參數調用父promise綁定的相應句柄,並返回該promise對象。
Promise.reject(reason)
返回一個狀態爲失敗的Promise對象,並將給定的失敗信息傳遞給對應的處理方法
Promise.resolve(value)
返回一個狀態由給定value決定的Promise對象。若是該值是thenable(即,帶有then方法的對象),返回的Promise對象的最終狀態由then方法執行決定;不然的話(該value爲空,基本類型或者不帶then方法的對象),返回的Promise對象狀態爲fulfilled,而且將該value傳遞給對應的then方法。一般而言,若是您不知道一個值是不是Promise對象,使用Promise.resolve(value) 來返回一個Promise對象,這樣就能將該value以Promise對象形式使用。
經過上面能夠詳細瞭解Promise的靜態方法,後來就是使用Promise實例,
建立Promise
Promise 對象是由關鍵字 new 及其構造函數來建立的。該構造函數會把一個叫作「處理器函數」(executor function)的函數做爲它的參數。這個「處理器函數」接受兩個函數——resolve 和 reject ——做爲其參數。當異步任務順利完成且返回結果值時,會調用 resolve 函數;而當異步任務失敗且返回失敗緣由(一般是一個錯誤對象)時,會調用reject 函數。
const myFirstPromise = new Promise((resolve, reject) => { // ?作一些異步操做,最終會調用下面二者之一: // // resolve(someValue); // fulfilled // ?或 // reject("failure reason"); // rejected });
想要某個函數擁有promise功能,只需讓其返回一個promise便可。
function myAsyncFunction(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = () => reject(xhr.statusText); xhr.send(); }); };
基礎示例
let myFirstPromise = new Promise(function(resolve, reject){ //當異步代碼執行成功時,咱們纔會調用resolve(...), 當異步代碼失敗時就會調用reject(...) //在本例中,咱們使用setTimeout(...)來模擬異步代碼,實際編碼時多是XHR請求或是HTML5的一些API方法. setTimeout(function(){ resolve("成功!"); //代碼正常執行! }, 250); }); myFirstPromise.then(function(successMessage){ //successMessage的值是上面調用resolve(...)方法傳入的值. //successMessage參數不必定非要是字符串類型,這裏只是舉個例子 console.log("Yay! " + successMessage); });
Promise.all的基礎使用
Promise.all() 方法接收一個promise的iterable類型(注:Array,Map,Set都屬於ES6的iterable類型)的輸入,而且只返回一個Promise實例, 那個輸入的全部promise的resolve回調的結果是一個數組。這個Promise的resolve回調執行是在全部輸入的promise的resolve回調都結束,或者輸入的iterable裏沒有promise了的時候。它的reject回調執行是,只要任何一個輸入的promise的reject回調執行或者輸入不合法的promise就會當即拋出錯誤,而且reject的是第一個拋出的錯誤信息。
const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'foo'); }); Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values); }); // expected output: Array [3, 42, "foo"]
輸出:
> Array [3, 42, "foo"]
Promise平常使用
平常開發狀況下咱們會常常跟Promise打交道,下面列舉平常使用方式,
先定義一個Promise方法,
api.js
function getData(){ return new Promise(resolve => { axios.get('xxxx').then(res => { resolve(res.data) }) } }
而後在組件裏面調用分紅兩種方式接收:一、async await,二、then,看我的喜愛使用哪一種方式。
async await方式
async function query(){ // res接收 let res = await api.getData(); }
then方式
function query(){ api.getData().then(res=>{ // res接收 }); }
Promise.all複雜使用
下面舉個四級聯動的例子介紹Promise.all的用法,能夠跟Array.map方法結合使用,以下所示,數組中包含選中值:one,two,three和four,以及選中值對應的列表:oneList,twoList,threeList和fourList,而且四組數據之間存在關聯關係。
let arry = [{ one: '', oneList: [], two: '', twoList: [], three: '', threeList: [], four: '', fourList: [] },{ one: '', oneList: [], two: '', twoList: [], three: '', threeList: [], four: '', fourList: [] },{ one: '', oneList: [], two: '', twoList: [], three: '', threeList: [], four: '', fourList: [] }] // 獲取全部oneList數據 Promise.all(arr.map(item => this.getOneList())) .then(promiseData => { //按順序輸出id對應的oneList 數據 arr.forEach((item,index) => { item.oneList = promiseData[index] }) }) // 獲取全部twoList數據 Promise.all(arr.map(item => this.getTwoList(item.one))) .then(promiseData => { //按順序輸出id對應的twoList 數據 arr.forEach((item,index) => { item.twoList = promiseData[index] }) }) // 獲取全部threeList數據 Promise.all(arr.map(item => this.getThreeList(item.two))) .then(promiseData => { //按順序輸出id對應的threeList 數據 arr.forEach((item,index) => { item.threeList = promiseData[index] }) }) // 獲取全部fourList數據 Promise.all(arr.map(item => this.getFourList(item.three))) .then(promiseData => { //按順序輸出id對應的fourList 數據 arr.forEach((item,index) => { item.fourList = promiseData[index] }) })
這樣就能批量獲取四級列表數據並賦值到arry數組上面,一開始個人解決思路並非這樣,而是在forEach裏面使用Promise,發現根本行不通,由於forEach自己就是異步的,因此還沒等結果返回就已經執行了。
錯誤使用方式
arry.forEach((item, index) => { item.oneList = this.getOneList(); item.twoList = this.getTwoList(item.one); item.threeList = this.getThreeList(item.one); item.fourList = this.getFourList(item.one); })
雖然很簡單,可是實際上行不通,必定要注意。
一、forEach不支持Promise
JavaScript ES6 promise for loop duplicate
How to return many Promises and wait for them all before doing other stuff
Promise.all結合async/await
理解和使用Promise.all和Promise.race
JAVASCRIPT中FOREACH的異步問題