原文地址: https://www.xiabingbao.com/po...javascript
本篇文章主要是想經過ES6中Promise提供的幾個方法,來實現諸如first、last、none、any等各類變體方法!html
在標準的ES6規範中,提供了Promise.all
和Promise.race
兩種,咱們首先來了解下這兩個方法是幹嗎的,方便咱們後面工做的展開。Promise.all中全部的Promise實例都處於完成狀態,該方法才進入完成狀態,不然任意一個被拒絕,則該方法進入拒絕狀態,並捨棄其餘全部完成的結果,拒絕緣由是第一個被拒絕的實例的緣由。Promise.race中任意的一個Promise實例變成完成狀態或者拒絕狀態,則race結束,race的結果即爲第一個變成最終狀態的結果!更詳細的能夠參考下阮一峯的文章Promise對象之Promise.all。java
在開始編寫各類變體方法以前,這裏咱們首先定義幾個一下子要使用的幾個Promise實例:es6
/** * 建立一個Promise對象的實例 * @param name {string} 該實例的名稱 * @param flag {boolean} 返回的結果狀態:完成仍是拒絕 * @param diff {number} 延遲的時間 */ var createPromiseCase = ( name, flag, diff ) => { return new Promise( ( resolve, reject ) => { setTimeout( () => { flag ? resolve( name ) : reject( new Error( 'testPromise is error, name: ' + name ) ); }, diff ); } ); }; var p1_suc_100 = createPromiseCase( 'p1-suc-100', true, 100 ); var p2_suc_500 = createPromiseCase( 'p2-suc-500', true, 500 ); var p3_suc_300 = createPromiseCase( 'p3-suc-300', true, 300 ); var p4_fail_400 = createPromiseCase( 'p4-fail-400', false, 400 ); var p5_fail_200 = createPromiseCase( 'p5-fail-200', false, 200 );
場景:一個頁面當前正處於loading狀態,同時請求了多個接口,不管哪一個接口正確返回結果,則loading效果取消!或者其餘的要獲取獲取第一個完成狀態的值。promise
這裏就要用到了Promise.first
了,只要任意一個Promise實例變成完成狀態,則Promise.first變成完成狀態。其實這裏並不適合Promise.race
方法,由於第一個變成拒絕狀態的實例也會激活Promise.race,post
if ( !Promise.first ) { // get first resolve result Promise.first = promiseList => { return new Promise( ( resolve, reject ) => { var num = 0; var len = promiseList.length; promiseList.forEach( pms => { Promise.resolve( pms ).then( resolve ).catch( () => { num++; if ( num === len ) { reject( 'all promises not resolve' ); } } ); } ); } ); }; }
調用方式:code
Promise.first([p4_fail_400, p2_suc_500, p3_suc_300]) .then(res => console.log(res)) // p3-suc-300 .catch(e => console.error(e))
能夠看到每次獲取的p3_suc_300的值,由於p4是失敗的狀態,p2的完成狀態沒有p3快,所以這裏獲取到了p3的結果。htm
與Promise.first對應的則是Promise.last
,獲取最後變成完成狀態的值。這裏與Promise.first不一樣的是,只有最後一個Promise都變成最終態(完成或拒絕),才能知道哪一個是最後一個完成的,這裏我採用了計數的方式,then
和catch
只能二選一,等計數器達到list.length時,執行外部的resolve。對象
if ( !Promise.last ) { // get last resolve result Promise.last = promiseList => { return new Promise( (resolve, reject) => { let num = 0; let len = promiseList.length; let lastResolvedResult; const fn = () => { if (++num===len) { lastResolvedResult ? resolve(lastResolvedResult) : reject('all promises rejected'); } } promiseList.forEach( pms => { Promise.resolve( pms ) .then(res => { lastResolvedResult = res; fn() }) .catch(fn); } ) } ) } }
調用方式:接口
Promise.last([p1_suc_100, p2_suc_500, p5_fail_200, p3_suc_300, p4_fail_400]) .then(res => console.log(res)) // p2-suc-500 .catch(e => console.error(e))
p2須要500ms才能完成,是最晚完成的。
Promise.none
與Promise.all正好相反,全部的promise都被拒絕了,則Promise.none變成完成狀態。該方法能夠用Promise.first來切換,當執行Promise.first的catch時,則執行Promise.none中的resolve。不過這裏咱們使用Promise.all來實現。
if ( !Promise.none ) { // if all the promises rejected, then succes Promise.none = promiseList => { return Promise.all( promiseList.map( pms => { return new Promise( ( resolve, reject ) => { // 將pms的resolve和reject反過來 return Promise.resolve( pms ).then( reject, resolve ); } ) } ) ) } }
調用方式:
Promise.none([p5_fail_200, p4_fail_400]) .then(res => console.log(res)) .catch(e => console.error(e)) // then的輸出結果: // [ // Error: testPromise is error, name: p5-fail-200, // Error: testPromise is error, name: p4-fail-400 // ]
兩個promise都失敗後,則Promise.none進入完成狀態。
Promise.any表示只獲取全部的promise中進入完成狀態的結果,被拒絕的則忽略掉。
if ( !Promise.any ) { // get only resolve the results Promise.any = promiseList => { let result = []; return Promise.all( promiseList.map( pms => { return Promise.resolve( pms ) .then( res => result.push( res ) ) .catch( e => { } ); } ) ).then( ( res ) => { return new Promise( ( resolve, reject ) => { result.length ? resolve( result ) : reject(); } ) } ) } }
調用方式:
Promise.any([p1_suc_100, p2_suc_500, p5_fail_200, p3_suc_300, p4_fail_400]) .then(res => console.log(res)) // ["p1-suc-100", "p3-suc-300", "p2-suc-500"] .catch(e => console.error(e))
最後一個的實現比較簡單,全部的promise都進入完成狀態,則返回true,不然返回false。
if (!Promise.every) { // get the boolean if all promises resolved Promise.every = promiseList => { return Promise.all(promiseList) .then(() => Promise.resolve(true)) .catch(() => Promise.resolve(false)); } }
調用方式:
Promise.every([p1_suc_100, p2_suc_500, p3_suc_300]) .then(result => console.log('Promise.every', result)); // Promise.every true Promise.every([p1_suc_100, p4_fail_400]) .then(result => console.log('Promise.every', result)); // Promise.every false
Promise還有各類方面的應用,不少類庫也都實現了相似的方法,這裏也僅僅是鄙人拙見,稍微實現了Promise的變體方法,加深下對Promise的理解。
原文地址: 蚊子的博客