几天前,我在YouTube上观看了一段有趣的视频,介绍了Broken Promises引入的James Snell。
您可以从他的repository的视频中找到一些很好的例子。
根据他所说,我们不应在承诺中包装纯粹的同步代码。而且,如果我们绝对需要一个函数来返回承诺,则可以使用
Promise.resolve() method
来同步解决该承诺。 重要的是,他还指出了同步运行代码并为所有其他promise分配省去了麻烦。
看完视频后,我调查了我的代码。想知道我是否做了与他在剪辑中提到的类似的事情。
让我给你看一些例子。
这是一个异步函数,等待诺言得到解决。
async getGameShotDetail(buffer: Buffer, fileSize: number): Promise<ShotDetail[]> {
const { latitude, longitude, shotType } = await somefunc()
const data = await Promise.all([
this.parseHoleNumber(shotType),
this.parseShotType(shotType),
this.parseCoordinate(this.sliceBufferIntoPieces(latitude)),
this.parseCoordinate(this.sliceBufferIntoPieces(longitude)),
]);
return some async func(data);
}
parseHoleNumber
方法数组中的前两个方法parseShotType
和Promise.all()
几乎是同一件事。它从二进制文件中读取数据,并且它们最终都返回一个数字数组作为Promise。
private parseHoleNumber(buffer: number[]): Promise<number[]> {
return new Promise((resolve, reject) => {
if (buffer.length < 0) {
reject([]);
}
/* tslint:disable:no-bitwise */
resolve(buffer.filter(n => n !== 0).map(holeNumber => holeNumber >> 3));
/* tslint:enable:no-bitwise */
});
}
我要在这里完成的工作是编写返回承诺的同步函数。问题是我不确定James Snell所说的代码是否写得很好。
据我所知,所有Array方法(包括push)都是同步的。而且我不确定将项目从new Promise(executor)
推送到数组是否安全。
我的代码中是否存在任何易受攻击的或错误使用的诺言?
private sliceBufferIntoPieces(
buffer: number[] | string[],
chunkSize: number = 4,
): Promise<Array<number[]>> {
const arr = [];
return new Promise((resolve, reject) => {
for (let i = 0; i < buffer.length; i += chunkSize) {
arr.push(buffer.slice(i, i + chunkSize));
}
arr.length > 0 ? resolve(arr) : reject([]);
});
}
private async parseCoordinate(buffer: Promise<Array<number[]>>): Promise<number[]> {
const itemsAreZero = (item): boolean => item === 0;
return Promise.resolve(
(await buffer) // Maybe this is bad?
.filter(buff => !buff.every(itemsAreZero))
.map(byte => +(this.read4byteItem(byte) / 360000).toFixed(6)),
);
}
我想亲自感谢詹姆斯的精彩演讲??
答案 0 :(得分:2)
您的代码中没有任何函数可以异步执行任何操作。 await somefunc
行运行之后,您正在执行的所有其他操作都是同步的,但是由于某些原因,您仍将所有内容包装在Promise.all
调用中。您可以通过删除不必要的Promise构造和Promise.resolve
s来解决此问题(并避免使用视频讨论的反模式):
async getGameShotDetail(buffer: Buffer, fileSize: number): Promise<ShotDetail[]> {
const { latitude, longitude, shotType } = await somefunc()
const data = [
this.parseHoleNumber(shotType),
this.parseShotType(shotType),
this.parseCoordinate(this.sliceBufferIntoPieces(latitude)),
this.parseCoordinate(this.sliceBufferIntoPieces(longitude)),
];
return some async func(data);
}
private parseHoleNumber(buffer: number[]) {
if (buffer.length < 0) {
// If you don't want processing to continue in getGameShotDetail, throw an error:
throw new Error('Buffer length negative??');
// Otherwise, just return an empty array:
// return [];
}
/* tslint:disable:no-bitwise */
return buffer.filter(n => n !== 0).map(holeNumber => holeNumber >> 3);
/* tslint:enable:no-bitwise */
});
}
private sliceBufferIntoPieces(
buffer: number[] | string[],
chunkSize: number = 4,
): Array<number[]> {
const arr = [];
for (let i = 0; i < buffer.length; i += chunkSize) {
arr.push(buffer.slice(i, i + chunkSize));
}
if (arr.length === 0) {
// Same as above - do you want to return an empty array, or stop execution entirely?
throw new Error('Buffer empty');
}
}
关于上述两个函数,如果缓冲区为空,请考虑-您实际上是要完全停止执行还是要继续使用空数组来执行?如果要停止执行,请抛出一个错误(带有throw
)-否则,请不要抛出该错误,只返回一个空数组。
由于sliceBufferIntoPieces
无需返回承诺,因此parseCoordinate
无需等待其解决:
private parseCoordinate(buffer: Array<number[]>): number[] {
const itemsAreZero = (item): boolean => item === 0;
return buffer
.filter(buff => !buff.every(itemsAreZero))
.map(byte => +(this.read4byteItem(byte) / 360000).toFixed(6))
}
还要记住,Typescript几乎总是可以推断出函数返回值的类型,而无需您显式指定它-除非您的后代强迫您注意返回类型,否则请不要理会那些返回值。