最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 当 forEach 遇上了 async 与 await

    正文概述 掘金(李国庆_seven)   2021-01-03   609

    前言

    最近在写一个小项目练手 Vue3koa ,在用 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 的执行。

    发现了这一问题后就关于 forEachasync 函数一起使用时的问题以及原理记录此文。

    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 关键字获取到值。


    起源地下载网 » 当 forEach 遇上了 async 与 await

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元