前言
最近在写一个小项目练手 Vue3
和 koa
,在用 koa
写后台路由接口的时候,遇到了这么一个问题:
当前有一个存有用户 id
的数组,例如:[1, 2, 3, ...]
,我需要使用 sql
语句查询每一个 id
对应的用户的用户名。下面写一下我最初的伪代码:
// id 数组
const arr = [1, 2, 3, ...]
const infoList = new Array(arr.length)
arr.forEach((id, index) => {
const sql = `select name from users where id='${id}';`
const res = exec(sql) // 这里有问题
infoList[index].id = id
infoList[index].name = res
})
最初的伪代码是这样的,解释一下,sql
语句你可以跳过,exec
是我封装的 mysql
的执行 sql
语句的方法。这个操作应该是异步的。所以我们的 res
是获取不到值的。
需要给 exec
前面加上 await
来执行它,这样当前的函数就必须是一个 async
函数了,所以代码可以写成下面这样:
const arr = [1, 2, 3, ...]
arr.forEach(async (id, index) => {
const sql = `select name from users where id='${id}';`
const res = await exec(sql)
infoList[index].id = id
infoList[index].name = res
})
这样看起来并没有什么不妥,但是当我这样写下来执行代码的时候就发现了问题,infoList
的每一项都是空的。理由只有一个:forEach
循环没有等待 await
的执行。
发现了这一问题后就关于 forEach
和 async
函数一起使用时的问题以及原理记录此文。
forEach
发现问题并且找到问题的根源后,我们就先来看一下 forEach
的原理,我尝试着根据 forEach
的用法,简单实现一下它:
Array.prototype.myForEach = function(callback, thisArg) {
for (let i = 0; i < this.length; i ++) {
callback.call(thisArg, this[i], i, this)
}
}
这样我们就可以使用我们写的 forEach 方法了:
const arr = [1, 2, 3]
arr.myForEach((item, index, array) => {
console.log(item, index)
})
正如所料是可以运行的,相信到这里问题也就迎刃而解了。
使用我们手写的 myForEach
实现以前的用例:
// id 数组
const arr = [1, 2, 3, ...]
arr.myForEach(async (id, index) => {
const sql = `select name from users where id='${id}';`
const res = await exec(sql)
infoList[index].id = id
infoList[index].name = res
})
可以看到 myForEach
的参数 callback
是一个异步函数,但是在内部进行调用的时候并没有使用 await
关键字来等待异步执行的结果,而是直接进行循坏,所以当然不会拿到结果。
解决
找到了问题后我们尝试着解决它,其实方法也很简单,就只需要让 callback
函数不要立即执行就好,而是等待异步任务的状态改变后执行,所以改造我们的 myForEach
函数:
Array.prototype.myForEach = async function(callback, thisArg) {
for (let i = 0; i < this.length; i ++) {
await callback.call(thisArg, this[i], i, this)
}
}
这样就可以确保每一次的 callback
函数内的代码是都可以准确的拿到值啦。
其他解决方式
当然除了改写原生的 forEach 方法还可以使用其他的循环结构,例如普通的 for
循环、for ... in ...
、for ... of ...
,这些循环结构都会在本身得异步函数作用域中执行,可以在其内部直接添加 await
关键字获取到值。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!