margin-js | kuworking

Gatsby11tyAstro|UnoCSS|SolidJS

Loops de JavaScript, diferencias entre FOR versus FOREACH

Ojo, este artículo no se ha actualizado desde hace más de 12 meses

Iterar sobre objetos 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

Tenemos el loop for que nos permite iterar en una secuencia de números

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

Tenemos otros loops (los pueds ver aquí), pero aquí lo compararé con el más moderno forEach

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"]

La diferencia entre ambos es que el primero responde a una programación imperativa y el segundo a una programación funcional o declarativo

  • 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

Dicho esto, entre ambos hay otra diferencia fundamental, el uso de await y async

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

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

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

  • 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

Esto 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