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
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(
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
result.then((data)=> {
let icon: egret.Bitmap = new egret.Bitmap(
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的的初級用法詳解了,希望可以幫助到開發者們。如果您有任何的意見和建議,歡迎您留言和我們共同交流探討。