En JavaScript, ¿en qué se diferencia la espera del resultado de una sincronización asíncrona de las llamadas sincronizadas?

Pregunta:

Estoy teniendo dificultades para entender el uso de llamadas a funciones async / await y sincronización regular en JavaScript.

Digamos que tengo dos funciones:

Función 1 :

async function doSomething() {
    const result = await doExpensiveOperation()
    const result2 = await doAnotherExpensiveOperation()
    return { result, result2 }
}

Función 2 :

function doSomething() {
    const result = doExpensiveOperation()
    const result2 = doAnotherExpensiveOperation()
    return { result, result2 }
}

Según mi entendimiento, estas dos funciones parecen equivalentes. En la Función 1, se ejecuta la primera operación y el programa necesita ESPERAR los resultados de esa operación antes de ejecutar la siguiente línea y luego necesita ESPERAR los resultados antes de ejecutar la declaración de return . ¿En qué se diferencia de la función 2, que ejecuta sus declaraciones de forma sincrónica?

Creo que la intención es que la Función 1 supuestamente desbloquea el hilo de ejecución de JavaScript y le permite ejecutar declaraciones más allá de la await pero eso no parece cumplir con la definición de "espera", que me parece que necesita "esperar" para resultados de algo.

Ayúdame a despejarme de este concepto básico.

Respuesta:

Tiene razón en que await "bloquea" la tarea actual. Pero puede haber más de una tarea pendiente de ejecución al mismo tiempo. Mientras una tarea espera algún resultado, se puede ejecutar otra.

Por ejemplo, supongamos que necesito hacer algo doSomething(1) y hacer algo doSomething(2) . Sin async / await, se ejecutarían uno tras otro, lo que provocaría una latencia prolongada. Pero con async, o equivalentemente con devoluciones de llamada, la ejecución se puede intercalar. Aquí hay una ilustración con ASCII-art:

  • Ejecución secuencial: se pierde el tiempo de espera.
     ┌───┬──────┬───┐ doSomething(1) │ │ WAIT │ │ └───┴──────┴───┘ ┌───┬──────┬───┐ doSomething(2) │ │ WAIT │ │ └───┴──────┴───┘ ├───────────────────────────────▶ time
  • Ejecución concurrente: el tiempo de espera se puede utilizar para ejecutar otra tarea.
     ┌───┬──────┬───┐ doSomething(1) │ │ WAIT │ │ └───┴──────┴───┘ ┌───┬──────┬───┐ doSomething(2) │ │ WAIT │ │ └───┴──────┴───┘ ├───────────────────────────────▶ time

Una tarea puede estar esperando por una variedad de razones, por ejemplo:

  • esperando la interacción del usuario, por ejemplo, que el usuario hace clic en un botón o concede un permiso
  • esperando una respuesta HTTP u otra interacción de red
  • esperando que se acabe el temporizador

Con Promises, cada código asincrónico / en espera se puede escribir de forma equivalente con devoluciones de llamada. Es solo que las devoluciones de llamada suelen ser menos convenientes. Aquí está su código original:

async function doSomething() {
    const result = await doExpensiveOperation()
    const result2 = await doAnotherExpensiveOperation()
    return { result, result2 }
}

Y aquí está el código traducido para usar devoluciones de llamada de promesa:

function doSomething() {
    return doExpensiveOperation().then(result => {
      return doAnotherExpensiveOperation().then(result2 => {
        return { result, result2 }
      })
    })
}

Tenga en cuenta que cada await presenta un orden claro. Las cosas antes de la espera deben completarse antes de que la espera continúe. Si desea que las dos tareas costosas tengan la oportunidad de ejecutarse al mismo tiempo, preferiría escribirlo así:

async function doSomething() {
    // spawn the tasks
    const task1 = doExpensiveOperation()
    const task2 = doAnotherExpensiveOperation()

    // wait for both tasks to complete
    const [result, result2] = await Promise.all([task1, task2])
    return { result, result2 }
}

Leave a Comment

Your email address will not be published.

Scroll to Top

istanbul avukat

-

web tasarım