Promise的用法講解

Promise是一個建構函式,其自身有resolve reject all 等方法,原型上有then catch 等方法。

本文會著重講解以下內容:

1、resolve和reject的用法。

2、all的用法。

3、重點講解then的使用。

本教程所用引擎版本:5.2.13

本教程原始碼連結:
       https://github.com/shenysun/PromiseCourse

本教程參考:

【ES6 Promise 用法講解】

http://www.cnblogs.com/whybxy/p/7645578.html

1、最簡單的Promise

let any_1 = new Promise((resolve, reject)=> {

setTimeout(()=> {

console.log("經過1s,開始執行");

resolve("Promise執行完畢")

}, 1000);

})

/**

* Creates a new Promise.

* @param executor A callback used to initialize the promise. This callback is passed two arguments:

* a resolve callback used resolve the promise with a value or the result of another promise,

* and a reject callback used to reject the promise with a provided reason or error.

*/

new(executor: (resolve: (value?: T | PromiseLike) => void, reject: (reason?: any) => void) => void): Promise;

Promise的建構函式接收一個函式的引數,此函式有兩個引數:resolve , reject,分別表示一步操作執行成功和非同步執行失敗的後的回撥函式。

執行上面程式碼顯而易見,一秒後會執行“經過1s,開始執行”,並呼叫resolve方法。

到了這裡會有很多人開始疑問,這個resolve是什麼,也並沒有用,並沒有執行。

2、resolve的使用

上文提到resolve , reject,分別表示一步操作執行成功和非同步執行失敗的後的回撥函式。 那麼Promise函式完畢之後如何讓這兩個函式執行呢?

執行下面程式碼:

let any_1 = new Promise((resolve, reject)=> {

setTimeout(()=> {

console.log("1s後執行");

resolve("Promise執行完畢")

}, 1000);

})

any_1.then((data)=> {

console.log(data);

})

控制檯LOG:

Promise物件呼叫then方法,then接收一個函式引數,並且會拿到Promise執行成功回撥resolve函式的引數。這即是Promise的作用了。簡單來講,就是能把原來的回撥寫法分離出來,在非同步操作執行完後,用鏈式呼叫的方式執行回撥函式。

3、鏈式操作的用法

Promise相對於普通的回撥函式(callback)來說從從表面上來說可以簡化層層回撥的寫法,Promise的精髓是“狀態”,用維護狀態、傳遞狀態的方式來使得回撥函式能夠及時呼叫,它比傳遞callback函式要簡單、靈活的多。

下面看一段程式碼:

/**順序執行Promise */

private orderGo() {

this.firPromise().then((data)=> {

console.log(data);

return this.secPromise();

})

.then((data)=> {

console.log(data);

return this.thirdPromise();

})

.then((data)=> {

console.log(data);

console.log("三個執行完畢");

})

}

按照順序,每隔一段時間執行一個非同步回撥,在firPromise方法中傳給resolve的資料,可以再接下來的then方法中拿到,下面執行結果:

firPromise secPromise thirdPromise 三個方法的定義如下:

private firPromise(): Promise{

let result = new Promise((resolve, reject)=> {

setTimeout(function() {

console.log("執行第一個Promise, 500ms");

resolve("第一個執行完畢");

}, 500);

})

return result;

}

private secPromise(): Promise{

let result = new Promise((resolve, reject)=> {

setTimeout(function() {

console.log("執行第二個Promise, 300ms");

resolve("第二個執行完畢")

}, 300);

})

return result;

}

private thirdPromise(): Promise{

let result = new Promise((resolve, reject)=> {

setTimeout(function() {

console.log("執行第三個Promise, 200ms");

resolve("第三個執行完畢")

}, 200);

})

return result;

4、reject的用法

到這裡大家應該對Promise有了大概的認知,前面筆者只介紹了resolve的用法,還沒有介紹reject的用法,下面通過一個簡單的例子來捕捉失敗的回撥:

private rejectPromise(): Promise{

let result = new Promise((resolve, reject)=> {

let math: number = Math.floor(Math.random() * 10);

if(math >= 5) {

resolve("隨機數大於5: " math);

} else {

reject("隨機數小於5");

}

})

return result;

}

呼叫 rejectPromise方法

this.rejectPromise().then( //reject的用法

(data)=> {

console.log(data);

},

(data)=> {

console.log(data);

}

)

上面這段程式碼,隨機數如果大於5代表成功了,反而代表失敗了執行reject方法,執行結果有兩種:

5、all的用法

Promise的 all 提供並行執行非同步操作的能力,並且在所有非同步操作執行完畢之後才執行回撥。依舊使用上面第一的三個方法,all用法如下:

// -------------all用法---------------

Promise.all([this.firPromise(), this.secPromise(), this.thirdPromise()])

.then((datas)=> {

console.log(datas);

})

// -------------all用法---------------

執行結果:

all方法並行執行三個Promise物件,並把所有非同步執行的結果放進一個陣列中傳遞給then,就是上面的datas。

6、在實際開發中的用法

先看一個在Egret上常用的方法getResByUrl的使用:

RES.getResByUrl("resource/assets/egret_icon.png", (data)=> {

let icon: egret.Bitmap = new egret.Bitmap(data);

this.addChild(icon);

}, this, RES.ResourceItem.TYPE_IMAGE);

API中:

function getResByUrl(url: string, compFunc?: Function, thisObject?: any, type?: string): Promise;

可以看到getResByUrl 載入一個路徑的圖片資源,載入完成後執行comFunc回撥函式,通過回撥函式載入此圖片資源,顯示出來。我們可以拆分一下這個步驟,如下:

private urlGetImg() {

let result: Promise= RES.getResByUrl("resource/assets/egret_icon.png");

result.then((data)=> {

let icon: egret.Bitmap = new egret.Bitmap(data);

icon.x = egret.MainContext.instance.stage.stageWidth - icon.width;

this.addChild(icon);

})

}

二者結果相同,都可以通過路徑把圖片載入出來。

下面另外一個例子,參考Nasus

建立5 * 5個物件,非同步依次執行一系列操作,效果如下圖。

本次所有行為執行完畢之後,才可以進入下一次操作。使用到tween第三方庫,原始碼如下:

private orderTW() {

for (let i = 0; i < 5; i ) {

for (let j = 0; j < 5; j ) {

let map: egret.Bitmap = new egret.Bitmap(RES.getRes("egret_icon_png"));

map.anchorOffsetX = map.width / 2;

map.anchorOffsetY = map.height / 2;

map.x = map.width * j;

map.y = map.height * i;

this._layer.addChild(map);

this._layer.x = egret.MainContext.instance.stage.stageWidth / 2 - this._layer.width / 2;

this._layer.y = egret.MainContext.instance.stage.stageHeight / 2 - this._layer.height / 2;

}

}

//當前下標

let index: number = 0;

//執行動作的Promise

let twPromise = () => {

console.log(`執行${index}次`);

return new Promise((resolve1, reject) => {

egret.Tween.get(this._layer.getChildAt(index)).to({

rotation: 30

}, 400).to({

rotation: -30

}, 400).to({

alpha: 0

}, 200).call(() => {

resolve1(index );

})

})

}

//切換物件的Promise

let orderPromise = () => {

return new Promise((resolve2, reject) => {

twPromise().then(() => {

if (index < this._layer.numChildren) resolve2(orderPromise())

else resolve2("執行完畢")

})

})

}

orderPromise();

}

定義兩個Promise方法,分別為tween動畫的twPromise和執行twPromise方法的orderPromise方法,orderPromise在初始的時候執行,執行此方法會呼叫twPromise方法和twPromise的then方法,其中then方法會呼叫index ,也就是一個物件執行一系列tween動畫後,切換下一個物件,然後通過resolve2(orderPromise())使整個過程走完。

小結

本教程通過初入Promise到完成一個簡單的Demo,由淺入深學習了Promise的用法,如果有興趣也可以學習下catch race的用法。通過本教程,您可以學到以下知識點:

· Promise是什麼

· Promise的常用兩個函式resolve reject的使用

· 鏈式操作和all的用法

以上就是Promise的的初級用法詳解了,希望可以幫助到開發者們。如果您有任何的意見和建議,歡迎您留言和我們共同交流探討。