Sequential Async Await

Parallel Async Await

Fastest Async Await

Rick'nMorty's async

Movies async/await

Descansa de las promesas un rato y has async await

/**Es preferible usar async a lo demas por su facilidad de interpretacion
 * Recuerda que las peticiones asincronas pueden responderse ahora, luego o nunca
 */

//Esta cosa se va a tardar por lo que trabaja como una peticion a una api
//esto representa a la api
const doSomethingAsync = () => { //crea la funcion
  return new Promise((resolve, reject) => { //la hacemos promesa
    (true) //retornamos las respuestas de una promesa
    ? setTimeout(() => resolve('Do Something Async'),3000) //hacemos que se tarde 
    : reject(new Error('Test Error')) //buena practica de hacer el error
  })
} //listo

//ejecutamos la funcion como asincrona
//esto reprepresenta la peticion a la api
const doSomething = async () => { //declaramos esta arrow function asincrona
  const something = await doSomethingAsync() //decimos que esta es la peticion asincrona, osea que la mandamos al eventloop hasta que retorne algo
  console.log(something) //hasta que retorne algo mandamos a imprimir
} 

//esto representa el flujo de trabajo del eventloop
console.log('Before') //imprimimos
doSomething() //ejecutamos esta funcion pero como es asincrona js la agrega al event loop
console.log('After') //imprimimos

//este es el modo en que hacemos peticiones asincronas teniendo manejando el error
const anotherFunction = async () => { //declara la funcion asincrona
  try { //este funciona como then 
    const something = await doSomethingAsync() //hace la peticion asincrona
    console.log(something) //hace lo que tenga que hacer normalmente
  } catch (error) {
    console.error(error) //maneja el error
  }
}

//esto representa el flujo de trabajo del eventloop
console.log('Before') //imprimimos
anotherFunction() //ejecutamos esta funcion pero como es asincrona js la agrega al event loop
console.log('After') //imprimimos
//para que funcione await debemos poner async antes de la funcion 
async function requestHandler(req, res){

    //await es una marca para que sepa el navegador que esta sentencia va a tomar tiempo
    //el codigo corre cada sentencia y por el await espera a que la sentencia se concluya
    const user = await User.findById(req.userId)
    const tasks = await Task.findById(user.tasksId)
    tasks.completed = true
    await tasks.save()
    res.send('Task Completed')
    
}
//este codigo no toma en cuenta errores

Si quieres hacer manejo de los errores

//para que funcione await debemos poner async antes de la funcion 
async function requestHandler(req, res){
    //try es el recorrido por defecto de las sentencias,
    //...  en caso de que ocurra un error, brinca, va a catch y regresa
    try{
        const user = await User.findById(req.userId)
        const tasks = await Task.findById(user.tasksId)
        tasks.completed = true
        await tasks.save()
        res.send('Task Completed')
    }catch(e){ //aqui en catch mandamos el error en especifico y regresamos al try
        res.send(e)
    }

}

cosas que toman tiempo:

crear archivos, editar archivos, buscar archivos, consulta a api, modulo filesystem, etc