SoFunction
Updated on 2025-03-10

How to elegantly extract data in loops in JavaScript

Preface

In this article, we will introduce two methods of extracting data within a loop: internal iteration and external iteration. Share it for your reference and learning. I won’t say much below. Let’s take a look at the detailed introduction together.

cycle

For example, suppose there is a function logFiles():

const fs = require('fs');
const path = require('path');

function logFiles(dir) {
 for (const fileName of (dir)) { // (A)
 const filePath = (dir, fileName);
 (filePath);
 const stats = (filePath);
 if (()) {
  logFiles(filePath); // (B)
 }
 }
}
logFiles([2]);

The loop starting from line A is used to record the file path. It is a combination of for-of loops and recursion (recursive calls on line B).

What should you do if you find some data (iteration files) in the loop useful, but don't want to record it?

Internal iteration

The first method to extract data in a loop is internal iteration:

const fs = require('fs');
const path = require('path');

function logFiles(dir, callback) {
 for (const fileName of (dir)) {
 const filePath = (dir, fileName);
 callback(filePath); // (A)
 const stats = (filePath);
 if (()) {
  logFiles(filePath, callback);
 }
 }
}
logFiles([2], p => (p));

This iterative method is similar to Array's .forEach(): the loop is implemented in logFiles() and call callback for each iterative value (row A).

External iteration

An alternative to internal iteration is external iteration: we implemented an iterable that can be used to help us implement with a generator:

const fs = require('fs');
const path = require('path');

function* logFiles(dir) {
 for (const fileName of (dir)) {
 const filePath = (dir, fileName);
 yield filePath;
 const stats = (filePath);
 if (()) {
  yield* logFiles(filePath); // (A)
 }
 }
}
for (const p of logFiles([2])) {
 (p);
}

If it is an internal iteration, logFiles() will call us ("push" to us). And this time, we will call it ("pull" over).

Note that in the generator, a recursive call must be made via yield*  (line A): if only logFiles() is called then it returns an iterable. But what we want is to yield each item in that iterable. This is what yield* does.

The generator has a very good feature, that is, the processing can be interlocked with internal iterations: whenever logFiles() creates another filePath, we can view it immediately, and logFiles() continues. This is a simple collaborative multitasking where yield pauses the current task and switches to another task.

Extended reading

Chapter “Iterables and iterators” in “Exploring ES6”.
Chapter “Generators” in “Exploring ES6”.

Original text: /2018/04/

Summarize

The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.