简体   繁体   English

性能差异(map(),forEach(),for())

[英]Difference in performance (map(), forEach(), for())

Recently I had some issues using built-in map() function on array in JavaScript, which I managed to solve by using standard for loop. 最近,我在JavaScript的数组上使用内置map()函数时遇到了一些问题,我设法通过使用标准的for循环来解决。 I've look through posts on StackOverflow to find out where is the difference between those two methods (and forEach() which I tested just for sake of it). 我已经查看了StackOverflow上的帖子,以找出这两种方法(以及仅为了测试而测试的forEach()之间的区别。 I understand that map() is creating a new array by executing the function provided, whereas forEach() (and I believe for as well) are not creating a new array. 据我所知, map()是通过执行提供的功能建立一个新的数组,而forEach()我相信for以及)不创建新阵列。

Could anyone please explain where is the difference in how the functions are executed? 谁能解释一下函数执行方式的不同之处?

Tested scenario: Frontend in ReactJS receives data from the backend over http request. 经过测试的场景:ReactJS中的前端通过HTTP请求从后端接收数据。 The received data contains array of objects, where one property is image in base64 string. 接收到的数据包含对象数组,其中一个属性是base64字符串中的image。 I defined the function which converted each image to image object (using Jimp), inverted the color, change to base64 and saved back in the array as JSX object to be displayed on the page. 我定义了一个函数,该函数将每个图像转换为图像对象(使用Jimp),反转颜色,更改为base64,然后以JSX对象的形式保存在数组中,以显示在页面上。 Three version of code looked as followed: 三个版本的代码如下所示:

FOR LOOP: 对于循环:

            console.log("before for");
            for(n of result) {
                console.log("inside for ", counter);
                await this.processImage(n, counter++);
            }
            console.log("end for");
            this.setState(() => {
                console.log("Rendered");
                return {
                    rows: result
                }
            })

FOREACH(): FOREACH():

            console.log("before foreach");
            result.forEach(async (n) => {
                console.log("inside foreach ", counter);
                await this.processImage(n, counter++);
                counter++;
            })
            console.log("end foreach");
            this.setState(() => {
                console.log("Rendered");
                return {
                    rows: result
                }
            })

MAP(): 地图():

            console.log("before map");
            result.map(async (n) => {
                console.log("inside map ", counter);
                await this.processImage(n, counter++);
                counter++;
            })
            console.log("end map");
            this.setState(() => {
                console.log("Rendered");
                return {
                    rows: result
                }
            })

I included the console.logs in the code above to show how I was testing the execution of the code. 我在上面的代码中包含了console.logs ,以显示我如何测试代码的执行情况。 In each scenario what I got was (before, inside x3, end, rendered) in the same order. 在每种情况下,我得到的都是相同的顺序(在x3内部,结束,渲染之前)。 Unfortunately, map() and forEach() didn't perform the whole image processing and what I could see on the page instead of an image was super-long string. 不幸的是, map()forEach()并没有执行整个图像处理,我在页面上看到的而不是图像是超长字符串。 The for loop didn't fail a single time. for循环没有一次失败。

I understand in this situation I probably don't need to use map() as I don't have to create a new array. 我知道在这种情况下,由于不必创建新数组,因此可能不需要使用map() I would still like to know why the result was not always guaranteed, so I can avoid issues in the future. 我仍然想知道为什么不能总是保证结果,所以将来可以避免出现问题。

I want to properly understand how those functions work, so I can use them correctly in the future. 我想正确地理解这些功能的工作原理,以便将来可以正确使用它们。 The documentation I read on is not very clear to me, I hope you guys can help! 我阅读的文档对我来说不是很清楚,希望大家能帮忙!

Thanks 谢谢

By using an async function inside .map and .forEach you fire and forget the asynchronous action, which means that you won't know when it finished. 通过在.map.forEach使用async函数,您将触发并忘记异步操作,这意味着您不知道它何时完成。 The async function does however return a Promise, and if you use .map you could collect them in an array, call Promise.all on that and await that: 但是, async函数的确会返回Promise,如果使用.map ,则可以将它们收集到数组中,然后在其上调用Promise.all并等待:

await Promise.all(result.map(async (n) => {
   console.log("inside map ", counter);
   await this.processImage(n, counter++);
   counter++; // why increase counter twice?
}));
// all processings are guaranteed to be done

This will execute all the processing in parallel , which is probably (way) faster than processing sequentially which you'd do with the for loop. 这将并行执行所有处理,这可能(比)用for循环顺序执行要快。 Using a .forEach you aren't able to wait for all results to arrive, and therefore you probably don't want to use it in most cases. 使用.forEach您无法等待所有结果到达,因此在大多数情况下,您可能不想使用它。


If you arent doing asynchronous things, for and .forEach would behave nearly equal, except for arrays with empty slots ( .forEach skips empty slots): 如果您不做异步操作,则for.forEach行为几乎相同,除了具有空插槽的数组( .forEach跳过空插槽):

for(const el of Array(3)) 
  console.log(el); // logs undefined three times

Array(3).forEach(console.log) // silence

.map behaves like .forEach just that it builds up an array with the returned values, just as you said. 正如您所说, .map行为类似于.forEach一样,它使用返回的值构建一个数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM