hand Inicio
hand JSBloqs
hand GutenBloqs

Loops de JavaScript, diferencias entre FOR versus FOREACH

El forEach nos permite programar de modo declarativo (lo cual acostumbra a ser mucho mejor), pero ojo con el{' '} await y el async, porque con el forEach no funcionan como esperaríamos

Prólogo

Iterar sobre objects es una de las operaciones más útiles en JavaScript ya que muchas veces los objetos representan la manera más versátil que tenemos para organizar nuestros datos

El problema de utilizar loops es que no es tan sencillo como parece, las opciones de las que disponemos son bastantes y vale la pena conocer las diferencias entre ellas

Aquí compararé el clásico for con el forEach, que pueden parecer lo mismo pero son entre distintos y muy distintos

El loop for con arrays y objects

El loop for nos permite iterar en una secuencia de números

  • En un array estos números pueden ser sus índices para luego tener acceso a sus valores
  • En un object necesitaremos transformar el objeto en array, y el código final resulta una pesadilla

En resumen, este loop ha quedado anticuado aunque es el que (normalmente) ofrece un mayor rendimiento

js
const myArray = [
'kuworking',
'Aprende desarrollo web en kuworking.com',
]

for (let i = 0; i < myArray.length; i++ ) // myArray.length es igual a 2
console.log(myArray[i])

// kuworking
// Aprende desarrollo web en kuworking.com

const myObject = {
name: 'kuworking',
description: 'Aprende desarrollo web en kuworking.com',
}

for (let i = 0; i < Object.entries(myObject).length; i++) {
console.log(Object.keys(myObject)[i])
console.log(myObject[Object.keys(myObject)[i]])
}

// name
// description
// kuworking
// Aprende desarrollo web en kuworking.com

Para iterar arrays y objetos tenemos otros loops más modernos, los tienes en la entrada Loops de JavaScript, diferencias entre FOR..IN versus FOR..OF

Pero aquí hablaremos del forEach, un loop distinto a todos los demás

El loop forEach

Y por qué es distinto a los demás? Porque nos permite programar de un modo funcional o declarativo y no imperativo

Diferencias?

  • Con el imperativo lo primero que lees es cómo lo haces, y luego ves el qué
  • Con el funcional lo primero que lees es el qué, y luego ves el cómo

Es algo tan básico como que delante de una estructura for con sus paréntesis y sus variables tendrás sí o sí que pararte y entretenerte si quieres saber qué pasa allí

Con un foreach ya sabrás la variable y que hay un foreach, no te hará falta entretenerte para tener una idea básica de lo que ocurre

Y esto te permite

  • Leer el código más rápido
  • Escribir el código más rápido

Funciona así

js
const myObject = {
name: 'kuworking',
description: 'Aprende desarrollo web en kuworking.com',
}
Object.entries(myObject).forEach(el => console.log(el))

// ["name", "kuworking"]
// ["description", "Aprende desarrollo web en kuworking.com"]

Hasta aquí la diferencia conceptual

Pero hay una diferencia práctica que importa y mucho

Await y Async con el forEach

Este código funciona como esperamos (voy a utilizar un for..of por comodidad)

js
const timeout = (method, ms) =>
new Promise(resolve =>
setTimeout(() => {
method()
resolve()
}, ms)
)

const myObject = {
name: 'kuworking',
description: 'Aprende desarrollo web en kuworking.com',
}

;(async () => {
for await (const [key, value] of Object.entries(myObject)) {
await timeout(() => console.log('key -> ' + key), 1000)
console.log('value: -> ' + value)
}
})()

// "key -> name"
// "value: -> kuworking"
// "key -> description"
// "value: -> Aprende desarrollo web en kuworking.com"

Es decir, esperamos 1 segundo, luego tenemos una impresión de la primera pareja de valores en orden, luego esperamos otro segundo, y entonces nos aparecen la segunda pareja de valores

Pero si queremos hacer lo mismo con forEach vemos que no funciona

js
const timeout = (method, ms) =>
new Promise(resolve =>
setTimeout(() => {
method()
resolve()
}, ms)
)

const myObject = {
name: 'kuworking',
description: 'Aprende desarrollo web en kuworking.com',
}

Object.entries(myObject).forEach(async ([key, value]) => {
await timeout(() => console.log('key -> ' + key), 1000)
console.log('value: -> ' + value)
})

// "value: -> kuworking"
// "value: -> Aprende desarrollo web en kuworking.com"
// "key -> name"
// "key -> description"

Aquí nos siguen apareciendo por orden, pero nos aparecen las 2 parejas de valores al mismo tiempo, en lugar de esperarnos 2 segundos nos esperamos sólo 1 segundo

Haz la prueba y pon un valor de 10 segundos

  • Con el for of esperarías 10 segundos, luego una pareja, luego 10 segundos más, luego la otra pareja
  • Con el forEach esperarás 10 segundos y verás las 2 parejas en la consola

Y eso por qué pasa?

Porque cada loop de forEach es en realidad una función independiente, no forma parte de un loop

En otras palabras, el forEach lanza tantas funciones como elementos tenga en el loop, y estas se ejecutan en paralelo, no hay ninguna secuencia

Conclusión?

Si necesitas ejecutar el loop de forma secuencial, con forEach no puedes

Tu elección es el loop for of, y si no puedes con la programación imperativa, tu amigo es reduce()

draw of me

Hola, tienes en mente desarrollar una web?

Si quieres, te ayudo

11ty para webs ultra-rápidaseleventy js
Gatsby para webs complejasgatsby js
WordPress para webs para el usuario finalwordpress

Escríbeme

Lista de correo: escribo algo de tanto en cuanto