我的编程空间,编程开发者的网络收藏夹
学习永远不晚

await在forEach中不起作用如何解决

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

await在forEach中不起作用如何解决

这期内容当中小编将会给大家带来有关await在forEach中不起作用如何解决,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

首先引一个很简单题目:给一个数组,每隔1s打印出来.这里我把我一开始在项目中的代码贴出来.(当然这里完全和业务无关的)

const _ = require('lodash');const echo = async (i) => {  setTimeout(() => {    console.log('i===>', i);  }, 5000);}let arrs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];const task = async () => {  _.forEach(arrs, async (i) => {    await echo(i);  })}const run = async () => {  console.log('run-start====>date:', new Date().toLocaleDateString())  await task() ;  console.log('run-end====>date:', new Date().toLocaleDateString())}(async () => {  console.log('start...')  await run();  console.log('end...')})()// start...// run-start====>date: 2018-8-25// run-end====>date: 2018-8-25// end...// i===> 1// i===> 2// i===> 3// i===> 4// i===> 5// i===> 6// i===> 7// i===> 8// i===> 9

上面的代码和输出已经给出了,很奇怪,这里的await并没有其效果.一开始因为是加了业务,是我的业务代码出了问题,然后我就把代码抽出来了,还是不起作用,当时我是真的对对await怀疑了。

最后还是给出问题的答案:

lodash的forEach和[].forEach不支持await,如果非要一边遍历一边执行await,可使用for-of

这里给出正确的代码:

const _ = require('lodash');const echo = async (i) => {  return new Promise((resolve,reject)=>{    setTimeout(() => {      console.log('i===>', i,new Date().toLocaleTimeString());      resolve(i) ;    }, 2000);  })}let arrs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];const task = async () => {  // _.forEach(arrs, async (i) => {  //  await echo(ji) ;  // })  // arrs.forEach(async (i )=> {  //   await echo(i) ;  // });  for (const i of arrs) {    await echo(i) ;  }}const run = async () => {  console.log('run-start====>date:', new Date().toLocaleDateString())  await task() ;  console.log('run-end====>date:', new Date().toLocaleDateString())}(async () => {  console.log('start...')  await run();  console.log('end...')})()// 输出start...run-start====>date: 2018-8-26i===> 1 20:51:29i===> 2 20:51:31i===> 3 20:51:33i===> 4 20:51:35i===> 5 20:51:37i===> 6 20:51:39i===> 7 20:51:42i===> 8 20:51:44i===> 9 20:51:46i===> 10 20:51:48run-end====>date: 2018-8-26end...

三、总结

当解决问题的时候,有时候可以使用排除法,比方说在这个例子中,我们知道await这个机制肯定是没问题的,如果真的有问题肯定不会轮到我测出来,那么其实剩下来的问题只能是for遍历的原因了.

因为我一开始是用lodash实现的,那么就可以想是不是lodash的forEach没有作(或者做了多余)await处理,此时就可以换种方式试试了,总的来说还是经验的问题吧。

补充:在 forEach 中使用 async/await 遇到的问题

一、问题描述

前几天,项目中遇到一个 JavaScript 异步问题:

有一组数据,需要对每一个数据进行一个异步处理,并且希望处理的时候是同步的。

用代码描述如下:

// 生成数据const getNumbers = () => { return Promise.resolve([1, 2, 3])}// 异步处理const doMulti = num => { return new Promise((resolve, reject) => {  setTimeout(() => {   if (num) {    resolve(num * num)   } else {    reject(new Error('num not specified'))   }  }, 2000) })}// 主函数const main = async () => { console.log('start'); const nums = [1, 2, 3]; nums.forEach(async (x) => {  const res = await doMulti(x);  console.log(res); }); console.log('end');};// 执行main();

在这个例子中,通过 forEach 遍历地将每一个数字都执行 doMulti 操作。代码执行的结果是:首先会立即打印 start、end 。2 秒后,一次性输出 1,4,9。

这个结果和我们的预期有些区别,我们是希望每间隔 2 秒,执行一次异步处理,依次输出 1,4,9。所以当前代码应该是并行执行了,而我们期望的应该是串行执行。

我们尝试把 forEach 循环替换成 for 循环:

const main = async () => { console.log('start'); const nums = await getNumbers(); for (const x of nums) {  const res = await doMulti(x);  console.log(res); } console.log('end');};

执行结果完全符合了预期:依次输出:start、1, 4, 9, end 。

二、问题分析

思路都是一样的,只是使用的遍历方式不一样而已,为什么会出现这样的情况呢?在 MDN 上查找了一下 forEach 的 polyfill 参考 MDN-Array.prototype.forEach() :

// Production steps of ECMA-262, Edition 5, 15.4.4.18// Reference: http://es5.github.io/#x15.4.4.18if (!Array.prototype.forEach) { Array.prototype.forEach = function(callback, thisArg) {  var T, k;  if (this == null) {   throw new TypeError(' this is null or not defined');  }  // 1. Let O be the result of calling toObject() passing the  // |this| value as the argument.  var O = Object(this);  // 2. Let lenValue be the result of calling the Get() internal  // method of O with the argument "length".  // 3. Let len be toUint32(lenValue).  var len = O.length >>> 0;  // 4. If isCallable(callback) is false, throw a TypeError exception.   // See: http://es5.github.com/#x9.11  if (typeof callback !== "function") {   throw new TypeError(callback + ' is not a function');  }  // 5. If thisArg was supplied, let T be thisArg; else let  // T be undefined.  if (arguments.length > 1) {   T = thisArg;  }  // 6. Let k be 0  k = 0;  // 7. Repeat, while k < len  while (k < len) {   var kValue;   // a. Let Pk be ToString(k).   //  This is implicit for LHS operands of the in operator   // b. Let kPresent be the result of calling the HasProperty   //  internal method of O with argument Pk.   //  This step can be combined with c   // c. If kPresent is true, then   if (k in O) {    // i. Let kValue be the result of calling the Get internal    // method of O with argument Pk.    kValue = O[k];    // ii. Call the Call internal method of callback with T as    // the this value and argument list containing kValue, k, and O.    callback.call(T, kValue, k, O);   }   // d. Increase k by 1.   k++;  }  // 8. return undefined };}

从上面的 polyfill 中的 setp 7 ,我们可以简单地理解成下面的步骤:

Array.prototype.forEach = function (callback) { // this represents our array for (let index = 0; index < this.length; index++) {  // We call the callback for each entry  callback(this[index], index, this); };};

相当于 for 循环执行了这个异步函数,所以是并行执行,导致了一次性全部输出结果:1,4,9 。

const main = async () => { console.log('start'); const nums = await getNumbers(); // nums.forEach(async (x) => { //  const res = await doMulti(x); //  console.log(res); // }); for (let index = 0; index < nums.length; index++) {  (async x => {   const res = await doMulti(x)   console.log(res)  })(nums[index]) } console.log('end');};

三、解决方案

现在,我们把问题分析清楚了。前面用 for-of 循环来代替 forEach 作为解决方案 ,其实我们也可以改造一下 forEach :

const asyncForEach = async (array, callback) => { for (let index = 0; index < array.length; index++) {  await callback(array[index], index, array); }}const main = async () => { console.log('start'); const nums = await getNumbers(); await asyncForEach(nums, async x => {  const res = await doMulti(x)  console.log(res) }) console.log('end');};main();

四、Eslint 问题

这时候 Eslint 又报了错:no-await-in-loop 。关于这一点,Eslint 官方文档 https://eslint.org/docs/rules/no-await-in-loop 也做了说明。

好的写法:

async function foo(things) { const results = []; for (const thing of things) {  // Good: all asynchronous operations are immediately started.  results.push(bar(thing)); } // Now that all the asynchronous operations are running, here we wait until they all complete. return baz(await Promise.all(results));}

不好的写法:

async function foo(things) { const results = []; for (const thing of things) {  // Bad: each loop iteration is delayed until the entire asynchronous operation completes  results.push(await bar(thing)); } return baz(results);}

其实上面两种写法没有什么好坏之分,这两种写法的结果是完全不一样的。Eslint 推荐的 “好的写法” 在执行异步操作的时候没有顺序的,“不好的写法” 中有顺序,具体需要用哪种写法还是要根据业务需求来决定。

所以,在文档的 When Not To Use It 中,Eslint 也提到,如果需要有顺序地执行,我们是可以禁止掉该规则的:

In many cases the iterations of a loop are not actually independent of each-other. For example, the output of one iteration might be used as the input to another. Or, loops may be used to retry asynchronous operations that were unsuccessful. Or, loops may be used to prevent your code from sending an excessive amount of requests in parallel. In such cases it makes sense to use await within a loop and it is recommended to disable the rule via a standard ESLint disable comment.

上述就是小编为大家分享的await在forEach中不起作用如何解决了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

await在forEach中不起作用如何解决

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

await在forEach中不起作用如何解决

这期内容当中小编将会给大家带来有关await在forEach中不起作用如何解决,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。首先引一个很简单题目:给一个数组,每隔1s打印出来.这里我把我一开始在项目中的代
2023-06-06

lombok注解不起作用如何解决

如果Lombok注解不起作用,可能有以下几种解决方法:确认是否安装了Lombok插件:在使用Lombok注解之前,确保已经安装了相应的Lombok插件。可以通过在IDE中搜索Lombok来查看是否已安装。确认是否在IDE中启用了Lombok
lombok注解不起作用如何解决
2023-10-28

Vue.config.productionTip=false不起作用如何解决

本篇内容主要讲解“Vue.config.productionTip=false不起作用如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Vue.config.productionTip=fa
2023-07-04

jquery .val()不起作用如何解决

本篇内容介绍了“jquery .val()不起作用如何解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!jquery .val()不起作用的
2023-07-04

@JsonInclude(JsonInclude.Include.NON_NULL)不起作用如何解决

这篇“@JsonInclude(JsonInclude.Include.NON_NULL)不起作用如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收
2023-07-02

async注解不起作用如何解决

如果使用的是Python 3.7及以上版本,需要确保使用的函数是异步函数,即使用了`async def`关键字定义的函数。另外,需要确保函数被正确地调用,即使用了`await`关键字。如果使用`async`注解而没有起作用,可能是由于以下原
2023-09-16

php7改php.ini不起作用如何解决

本篇内容主要讲解“php7改php.ini不起作用如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“php7改php.ini不起作用如何解决”吧!php7改php.ini不起作用的解决办法:
2023-07-04

idea中@Data标签getset不起作用如何解决

这期内容当中小编将会给大家带来有关idea中@Data标签getset不起作用如何解决,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。spring cloud中使用@Data标签,不用手动添加get set
2023-06-06

如何解决Lombok注解不起作用的问题

本篇内容介绍了“如何解决Lombok注解不起作用的问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Lombok注解不起作用场景:减少实体类
2023-06-20

如何解决php header不起作用的问题

本篇内容介绍了“如何解决php header不起作用的问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!php header不起作用的方法:
2023-06-20

idea更新maven包不起作用如何解决

有几种可能的解决方案可以尝试解决Maven包更新不起作用的问题:1. 清除Maven本地存储库:在Maven的本地存储库中,可能存在旧版本的包。尝试删除本地存储库中的文件夹(默认路径为:C:\Users\your_username\.m2\
2023-09-16

IDEA断点调试不起作用如何解决

本文小编为大家详细介绍“IDEA断点调试不起作用如何解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“IDEA断点调试不起作用如何解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。IDEA断点调试,断点不起作用
2023-07-05

php屏蔽警告不起作用如何解决

这篇文章主要介绍“php屏蔽警告不起作用如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“php屏蔽警告不起作用如何解决”文章能帮助大家解决问题。php屏蔽警告不起作用的解决办法:1、打开php
2023-07-04

cad安全系统不起作用如何解决

今天小编给大家分享一下cad安全系统不起作用如何解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
2023-03-06

linux自动补全不起作用如何解决

如果Linux的自动补全功能不起作用,可以尝试以下几种解决方法:1. 确保已经安装了tab补全的相关软件包,例如bash-completion。可以使用以下命令来安装软件包:```shellsudo apt-get install bash
2023-08-29

js中onbeforeunload不起作用怎么解决

如果在JavaScript中使用`onbeforeunload`事件,但发现它不起作用,则可能有以下几种原因和解决方法:1. 浏览器限制:某些浏览器可能会限制`onbeforeunload`事件的使用。例如,某些浏览器只允许在用户关闭浏览器
2023-08-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录