「这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战」
问题
在做根据Swagger文档进行代码生成的过程中,因为服务端规范采用@ApiModal
对数据结构进行了注解,导致这一行为覆盖了原本swagger的命名生成规则,而用户定义的注解是不规范的,存在中文注解的概率基本是100%,但生成的ts代码类型命名又不能是中文,因此需要对可能存在的中文命名进行翻译,所以就产生了今天这个话题:用forEach进行异步操作,await了个寂寞.
番外话:
翻译采用的是谷歌翻译:@vitalets/google-translate-api
下面上伪代码(忽略代码签证健壮性问题,随手写,不是重点):
const translate = require('@vitalets/google-translate-api')
/** 递归翻译符合Json Scheme协议数据类型为'object'和'array'的title字段 */
const translateZhToEn = async ()=>{
return async function loopTranslate(data){
const {properties, title, type} = data || {}
if(type==='array' || type === 'object'){
data['title'] = await translate(title, { to: 'en', tld: 'cn' })
Object.keys(properties).forEach(async (key)=>{
const {properties, title, type} = properties[key]
if(type==='array' || type === 'object'){
await loopTranslate(properties[key])
}
})
}
}
}
// 符合Json Scheme的数据
const data = {}
translateZhToEn()(data)
按照上面理想的例子,按照脑子180码快速旋转运算,自信是没问题的。但运行的时候,傻眼了,并没有按照正常的输出,按逻辑是:下面数据结构的掘金用户
和用户标签
需要全部被翻译成中文,但实际上并没有!那就得找问题了!
{
title:'掘金用户',
type: 'object',
properties:{
id: {type: 'string'},
user_name: {type: 'string'},
label: {
title: '用户标签',
type: 'object',
properties: {
label_id: {type: 'string'},
label_name: {type: 'string'}
}
}
}
}
解决问题
问题很明显,递归异步并没有按我们想象中走,打个断点调试一下,很快就能确定是forEach
闹了鬼,本着负责任的代码,去看了forEach
的polyfill
,上代码:
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback, thisArg) {
var T, k;
if (this == null) {
throw new TypeError(' this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (typeof callback !== "function") {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = thisArg;
}
k = 0;
// 重点代码块
while (k < len) {
var kValue;
if (k in O) {
kValue = O[k];
callback.call(T, kValue, k, O);
}
k++;
}
};
}
看完是不是一目了然,while
循环内部只是执行了callback
方法,也就是forEach
的回调方法体,对于是异步函数,它并没有做任何判断,也并没有做任何处理,因此这里使用async/await
对于结果返回值顺序,它是不保证的。换句话说,forEach
循环异步在走,但也不妨碍主程序往下走,因此当主程序在异步结束前去操作对应的值,此时的值并不是都已经被forEach
处理完成的。
扩展下,就算你在forEach
的回调函数使用了break
,也并不能结束整个数据的遍历过程。那针对这类问题如何解决呢?
- 直接采用
for
循环 - 采用
for ... of