简体   繁体   中英

Asynchronous JavaScript: Proper way to make loops?

Last few days I'm thinking about JavaScript. Lot of frameworks offer functions only in asynchronous/promises way. But as I'm used to program in synchronous languages (PHP, Python, ...), I struggle with some basic ideas.

For example:

How to make loops with asynchronous function properly?

Let's say we have function nextValue() which returns string from some list of words. Our task is find word "Foo" in this list and print the index where the "Foo" word is located.

If the nextValue() function was synchronous, we could do it very easy:

 var found = false; for (var i = 0; !found; i++) { if (nextValue() == 'Foo') { console.log("'Foo' found at index " + i); found = true; } } 

But if the function was asynchronous, the only idea I've got is to make function and call it recursively until we find the "Foo" word:

 var i = 0; (function checkNextValue(){ nextValue(function(value){ if (value == 'Foo') { console.log("'Foo' found at index " + i); } else { i++; checkNextValue(); } }); })(); 

But I see few problems here:

  1. The asynchronous example is much harder to read. Imagine if we needed two nested loops or even more.
  2. RAM usage. What if the "Foo" value will be at index 1000? There will be 1000 running functions in the memory "thanks" to the recursion.
  3. And it's complicated in general and much harder to write the code, or even re-use the code in another place (we can't simply return value, we are forced to use callback or promise again).

What am I missing here? Thanks for you ideas :-)

How to make loops with asynchronous function properly?

Javascript adopts the concept of iteration, more likely others languages do, so, iteration doesn't really take care about sync/async code execution. There are many ways to achieve async iteration:

  1. Iterators and Generators
  2. Observables
  3. Async Iteration

are the more clean and eloquent ways.

The asynchronous example is much harder to read. Imagine if we needed two nested loops or even more.

Async code execution is often harder to read than the sync one, by the way, you can write a clean way. Let's do it implementing something like Array#extras

 Array.prototype.asyncForEach = function asyncForEach(callback, context = null) { const self = this; let index = 0; function iterate() { setTimeout(iteration, 1500); } function iteration() { callback.call(context, self[index], index, self); index += 1; if(self.length > index) { iterate(); } } return iterate(); }; ['hello dear', 'how are you?', 'I am fine, thanks'] .asyncForEach((item, index, list) => { console.log(Date.now(), `Iteration at {i: ${index}}`, item); }) ; 

RAM usage. What if the "Foo" value will be at index 1000? There will be 1000 running functions in the memory "thanks" to the recursion.

Of course RAM usage is a big concern, but, you have to mind that Javascript is based on non blocking I/O , so, your async iteration will take less than a normal sync code takes.

And it's complicated in general and much harder to write the code, or even re-use the code in another place (we can't simply return value, we are forced to use callback or promise again).

This regards all the languages, you're quite new here, you will find it comfortable as long as you keep going working with Javascript!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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