简单的使用场景
Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
JavaScript有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务。这个模型与其它语言中的模型截然不同,比如 C 和 Java。[2]
(在本轮 事件循环 运行完成之前,回调函数是不会被调用的。)
比如:
function t(){
return Promise.resolve('aaa')
.then(data => {
console.log("then1: ", data); })
.then(data => {
console.log("then2: ", data); return 'bbb'; })
.then(data => {
console.log("then3: ", data); return Promise.resolve('ccc'); })
.catch(err => {
console.log("eee"); return Promise.reject('eee'); });
}
function main(){
console.log("main start");
t()
.then(data => {
console.log("333: ", data); })
.catch(err => {
console.log("eee"); return 'ggg'});
console.log("main end");
}
main();
其实际输出如下:
$ node a.js
main start
main end
then1: aaa
then2: undefined
then3: bbb
333: ccc
但是实际上我们想让t()做完再输出main end,那么我们用一下promise的then就可以了:
function t(){
return Promise.resolve('aaa')
.then(data => {
console.log("then1: ", data); })
.then(data => {
console.log("then2: ", data); return 'bbb'; })
.then(data => {
console.log("then3: ", data); return Promise.resolve('ccc'); })
.catch(err => {
console.log("eee"); return Promise.reject('eee'); });
}
function main(){
console.log("main start");
t()
.then(data => {
console.log("333: ", data); })
.then(
data => {
console.log("main end");}
);
}
main();
那么输出变为:
$ node a.js
main start
then1: aaa
then2: undefined
then3: bbb
333: ccc
main end
实际用例
# 1 这是被调用的函数
public add(
options: IGroundVechicleOptions = {
}
) {
... <此处被作者省略>
// make sampledPositions clampToGround
let addedPromise = sampleTerrainMostDetailed(
this._viewer!.terrainProvider,
sampledPositions
).then(() => {
... <此处被作者省略>
... <处理数据>
console.log("end adding vehicle with id: ", vehicleID, " is added!", this._showFlags.keys());
});
return addedPromise;
}
我们的目标是让add里的
console.log("end adding vehicle with id: “, vehicleID, " is added!”, this._showFlags.keys());
这一句输出完成再执行:
this.groundVehicle.getIDs();
具体做法如下:
# 2 调用上面的函数
public initGroundVehicle() {
// init the ground Vehicle
this.groundVehicle = new _GV(<Viewer>this.cmap.viewer);
this.groundVehicle.add(options)
.then(ids => {
console.log("promise resolved!");
// update the vehicle id list
...<获取处理好的数据>
this.vehicleIDList = this.groundVehicle.getIDs();
}, () => {
// reject func, do nothing
})
.then(tmp1 => {
console.log("tmp1 nothing!");
})
.then(tmp2 => {
console.log("tmp2 nothing!");
});
}
其实上面最关键的步骤在于add函数的返回值:
return addedPromise;
返回的是一个新的promise,这个promise承诺的是之前的回调函数的完成。具体请看[1]中的链式调用。
使用 Promise 时,会有以下约定[1]:
- 1 在本轮 事件循环 运行完成之前,回调函数是不会被调用的。
- 2 即使异步操作已经完成(成功或失败),在这之后通过 then() 添加的回调函数也会被调用。
- 3 通过多次调用 then() 可以添加多个回调函数,它们会按照插入顺序进行执行。
Promise 很棒的一点就是链式调用(chaining)。
Refer
- [1] promise的具体使用
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises - [2] js的并发模型和事件循环
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop#%E6%89%A7%E8%A1%8C%E8%87%B3%E5%AE%8C%E6%88%90 - [3] 开源项目中对于promise的实际应用https://github.com/CesiumGS/cesium/blob/f05522e405137591c591f73dd660bd1ba5d625a7/Source/Core/sampleTerrainMostDetailed.js