Should we use _.foreach () or better for native for the loop in TypeScript

I just started working on a new project working with TypeScript. I am leaving from another project that also worked with TypeScript. Since native for the loop in TypeScript is available, we decided (the old project team) to use this one. Espacialy was much more convenient for me to write a for loop related to my java background.

Now in the new project, they use the _.foreach () loop everywhere to iterate over arrays.

What I'm wondering is there any performance difference between native TypeScript for and _.foreach ()

I created a small test in jsperf so that the seam is more or less the exact same speed ...

https://jsperf.com/foreach-vs-forof/12

TypeScript For

for (let num: string of list){ console.log(num); } 

In javascript

 var list = "9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9".split(); //Transpiled TypeScript for of | **19,937 ยฑ5.04% for (var _i = 0, list_1 = list; _i < list_1.length; _i++) { var num = list_1[_i]; console.log("" + num); } //lodash | 20,520 ยฑ1.22% _.forEach(list, function(item) { console.log("" + item) }); 

Imho, I would prefer the TypeScript native to become more readable to me.

What do you suggest using? Are there any other points to use or better _.forEach

+6
source share
3 answers

I have no experience with typing outside of my reading, but I have some experience with ES6 / ES2015. for of was and remains part of the ES2015 specification, which has been finalized. I would read this article on for of from MDN.

Here are some similarities and differences for for of and forEach (and this is the same as I found and know now):

  • forEach in lodash works with collections that are arrays, objects, or strings.

  • native forEach works with arrays, maps, and sets.

  • for of works on all for of Iterables : arrays, strings, TypedArrays, maps, sets, DOM collections, and generators.

I would read this for of chapter from Exploring ES6 (Exploring ES6 is an excellent read. It is very thorough. It is also free online). Some things from this that stand out to me as excellent for of those that are not intended for forEach ,

break and continue working inside the loops

break and continue not exposed in forEach . The closest thing you can get to continue in forEach is to use return which is actually pretty much the same. Regarding break although I donโ€™t see an alternative (but do not discount lodash, because most of the things that require breaks, such as finding and returning one item, are already covered by most of the lodash library).

It should also be noted that the await keyword from async / await can be used inside for of where forEach makes it quite difficult to stop the surrounding block from waiting for the promises expected in the forEach block, however, you can use forEach although using map or reduce can make the wait much easier than forEach (depending on your familiarity with these features). Below are three separate implementations awaiting promises both sequentially and in parallel using, for of , forEach , and reduce and map , to see possible differences.

 const timeout = ms => new Promise(res => setTimeout(() => res(ms), ms)); const times = [100, 50, 10, 30]; async function forOf() { console.log("running sequential forOf:"); for (const time of times) { await timeout(time); console.log('waited ${time}ms'); } console.log("running parallel forOf:"); const promises = []; for (const time of times) { const promise = timeout(time).then(function(ms) { console.log('waited ${ms}ms'); }); promises.push(promise); } await Promise.all(promises); }; async function forEach() { console.log("running sequential forEach:"); let promise = Promise.resolve(); times.forEach(function(time) { promise = promise.then(async function() { await timeout(time); console.log('waited ${time}ms'); }); }); await promise; console.log("running parallel forEach:"); const promises = []; times.forEach(function(time) { const promise = timeout(time).then(function(ms) { console.log('waited ${ms}ms'); }); promises.push(promise); }); await Promise.all(promises); }; async function reduceAndMap() { console.log("running sequential reduce:"); const promise = times.reduce(function(promise, time) { return promise.then(async function() { await timeout(time); console.log('waited ${time}ms'); }); }, Promise.resolve()); await promise; console.log("running parallel map:"); const promises = times.map(async function(time) { const ms = await timeout(time) console.log('waited ${ms}ms'); }); await Promise.all(promises); } forOf().then(async function() { await forEach(); await reduceAndMap(); }).then(function() { console.log("done"); }); 

Using Object.entries in ES2017, you can easily and precisely iterate over objects with their enumerated properties and values. If you want to use it now, you can use one of the polyphiles here . Here is an example of how it would look.

 var obj = {foo: "bar", baz: "qux"}; for (let x of Object.entries(obj)) { // OK console.log(x); // logs ["foo", "bar"] then ["baz", "qux"] } 

and here is an implementation with a quick polyfill I wrote. Usually, you also use an array destructuring, which splits the key and value into its own variables, for example:

 var obj = {foo: "bar", baz: "qux"}; for (let [key, val] of Object.entries(obj)) { // OK console.log(key + " " + val); // logs "foo bar" then "baz qux" } 

You can also use Object.entries with forEach as follows:

 var obj = {foo: "bar", baz: "qux"}; console.log("without array destructuring"); Object.entries(obj).forEach((x) => { // OK const key = x[0], val = x[1]; console.log(key + " " + val); // logs "foo bar" then "baz qux" }); console.log("with array destructuring"); Object.entries(obj).forEach(([key, val]) => { // OK console.log(key + " " + val); // logs "foo bar" then "baz qux" }); 

forEach first argument is the default type of functionality you get from let in a for or for of loop, which is a good thing. By this, I mean that if something asynchronous happens inside the variable for this iteration, it will be limited to only a specific part of this loop. This forEach property is not actually associated with let, but with the scope and function closures in JavaScript, and the alternative is that they are not block scopes. For example, see what happens here when var is used:

 const arr = [1,2,3,4,5,6,7,8,9]; for(var item of arr) { setTimeout(() => { console.log(item); }, 100); } 

Unlike using let or foreach.

 const arr = [1,2,3,4,5,6,7,8,9]; const timeout = 100; console.log('for of'); for(let item of arr) { setTimeout(() => { console.log(item); }, timeout); } setTimeout(() => { console.log('foreach'); arr.forEach((item) => { setTimeout(() => { console.log(item); }, timeout); }) }, timeout*arr.length); 

Once again, I note the difference between using var and let or foreach . The difference is that the var variable rises to the top of the scope of the function (or file if it is not in the function), and then the value is reassigned to the entire scope, so the loop reaches its end and assigns item for the last time. and then each settimeout function writes this last item . Whereas with let and foreach , the item variable is not overwritten because item limited to a block (when let is used) or a function (when foreach is used).

Between forEach and for of you just need to decide which one is best for your current job (for example, you need a break or you need to use Maps, Sets or for of Generators). In addition, I feel that there is no particular reason for the collections on which they work with their basic functions. Also, when working with collections that can use either forEach or for of it, mainly only for personal preferences, since they do the same thing at about the same speed (and speeds can change at any time depending on the interpreter). I feel that the special benefits of lodash are its various other functions, which in fact can save you a lot of time writing code yourself, such as displaying, reducing, filtering, and searching. Since you feel most comfortable writing for of I suggest you keep writing this that way, but as soon as you start writing in lodash, using other functions you can begin to feel more comfortable writing the lodash path to it.

Edit:

Looking through your code, I noticed an error while creating your list. In the end you only had .split() and you should have .split(",") . You created a list of length 1 of the entire line and repeated once for that line, so the tests were so similar. I restarted the tests. Here they are. I still wonโ€™t worry about performance, as it seems to change every time it starts.

+3
source

I can not comment on lodash, I have not used it. But below is some background that might help.

'For of' was introduced in TypeScript 1.5 to loop around each element, for example. list of arrays. If you study the JS output (and depending on whether you are configured for ECMA Script 5 or 6), you should find that in the case of ECMASCript5 the output of both below will be identical. See this article for related background readings and how ES6 / 2015 targeting will impact the outcome.

Regarding the implementation of forEach TypeScript, there is an interesting discussion about GitHub here . Especially around the conditional exit from the loop.

 for (let line of v.lineEntry) { } for (var _i = 0, list_1 = list; _i < list_1.length; _i++) { } 
+2
source

Based on your test, I added another one using my own Array.prototype.forEach :

 list.forEach(function(item) { console.log("" + item) }); 

This is really my favorite method, as itโ€™s actually much easier to type. Also its closer to other things that you might want to do with an array, for example. map / filter , etc.

Please note that http://jsperf.com/foreach-vs-forof/9 all three do not have a plausible performance difference.

+2
source

Source: https://habr.com/ru/post/1244722/


All Articles