let currentProduct;

for (let i = 0; i < products.length; i++) { 
    currentProduct = products[i];

    subscription.getAll(products[i]._id)
        .then((subs) => {
            update(subs, currentProduct);
        });
}

Estoy usando bluebird, los métodos getAll y actualización volver promesas. ¿Cómo puedo decir «Esperar hasta que las dos promesas de retorno, a continuación, actualizar el currentProduct valor»? Soy bastante nuevo en JS…

  • ¿Por qué esta pregunta etiquetado async-esperan? ¿Quieres usar esta característica?
InformationsquelleAutor Jumpa | 2017-12-28

3 Comentarios

  1. 10

    Este va a ser sencilla si se puede utilizar async/await:

    //Make sure that this code is inside a function declared using
    //the `async` keyword.
    let currentProduct;
    
    for (let i = 0; i < products.length; i++) { 
        currentProduct = products[i];
    
        //By using await, the code will halt here until
        //the promise resolves, then it will go to the
        //next iteration...
        await subscription.getAll(products[i]._id)
            .then((subs) => {
                //Make sure to return your promise here...
                return update(subs, currentProduct);
            });
    
        //You could also avoid the .then by using two awaits:
        /*
        const subs = await subscription.getAll(products[i]._id);
        await update(subs, currentProduct);
        */
    }

    O si sólo se puede utilizar texto promesas, puede crear un bucle a través de todos sus productos, y poner cada promesa en el .then de el último bucle. De esa manera, sólo avanzar a la siguiente cuando el anterior se ha resuelto (aunque se han reiterado todo el lazo de la primera):

    let currentProduct;
    
    let promiseChain = Promise.resolve();
    for (let i = 0; i < products.length; i++) { 
        currentProduct = products[i];
    
        //Note that there is a scoping issue here, since
        //none of the .then code runs till the loop completes,
        //you need to pass the current value of `currentProduct`
        //into the chain manually, to avoid having its value
        //changed before the .then code accesses it.
    
        const makeNextPromise = (currentProduct) => () => {
            //Make sure to return your promise here.
            return subscription.getAll(products[i]._id)
                .then((subs) => {
                    //Make sure to return your promise here.
                    return update(subs, currentProduct);
                });
        }
    
        //Note that we pass the value of `currentProduct` into the
        //function to avoid it changing as the loop iterates.
        promiseChain = promiseChain.then(makeNextPromise(currentProduct))
    }

    En el segundo fragmento, el bucle se establece el conjunto de la cadena, pero no ejecuta el código dentro de la .then inmediatamente. Su getAll funciones no se ejecutan hasta que cada uno antes de que uno se ha resuelto a su vez (que es lo que quieres).

    • Si utiliza await, también se usa en lugar de la then llamada
    • Estás en lo correcto. Usted podría utilizar esperan para obtener el resultado de la getAll, a continuación, pasar a update en la línea siguiente con otro aguardan. Pero lo que hay es todavía válida y he sido conocido para mezclar y combinar mi espera y thens. Yo diría que es hasta OP discreción en cuanto a qué estilo prefiere.
    • Por lo tanto, dos anidada esperan o esperan/a continuación, haga?
    • He editado el post para incluir un ejemplo de lo que un par de espera vería, ver el comentado sección en el primer fragmento.
    • La promesa de la cadena sería más simple con la recursividad y un poco menos simple usando reducir (ver mi respuesta). Esa respuesta también resuelve o rechaza algo algo sano, especialmente cuando se rechazó debido a que usted necesita saber lo lejos que se consiguió.
    • El uso de await es definitivamente más limpio. Usted no debe usar then dentro de un async función a menos que necesite el segundo argumento.
    • Cómo captar el momento, mientras que esto promete ciclo terminado? Me refiero a que tengo que añadir algo de código después de todas las promesas de procesamiento terminado(después de la última «, luego en» terminar). ¿Cómo puedo hacer eso?
    • Ya que cada uno «, luego en» cadenas de la última, sólo tienes que añadir en el .then de la promesa de la cadena después de que el ciclo ha terminado. por ejemplo, después de que el bucle: promiseChain.then(() => {/* do your thing */})
    • impresionante, muchas gracias !

  2. 7

    Esto es lo que yo haría:

    for (let product of products) { 
      let subs = await subscription.getAll(product._id);
      await update(subs, product);
    }

    Sin necesidad manualmente la cadena de promesas o recorrer las matrices índice 🙂

    • Yo estaba tratando de su código y creo que es la más elegante. De todos modos te estás perdiendo de «permitir» para el producto dentro de la para. Me di cuenta de que ya me estaba poniendo un UnhandledPromiseRejectionWarning…podría usted por favor editar el código y añadir algo para manejar una promesa de rechazo? Muchas gracias de antemano. EDIT: no importa que debo utilizar try/catch…
  3. 2

    Es posible que desee mantener un seguimiento de cuáles son los productos que he procesado porque cuando uno fracasa, usted no tiene idea de cuántos tuvieron éxito y usted no sabe cuál es la correcta (si el rollo de la espalda) o reintentar.

    La async «bucle» podría ser una función recursiva:

    const updateProducts = /* add async */async (products,processed=[]) => {
      try{
        if(products.length===0){
          return processed;
        }
        const subs = await subscription.getAll(products[0]._id)
        await update(subs, product);
        processed.push(product[0]._id);  
      }catch(err){
        throw [err,processed];
      }
      return await updateProducts(products.slice(1),processed);
    }

    Sin async puede utilizar la recursividad o reducir:

    //using reduce
    const updateProducts = (products) => {
      //keep track of processed id's
      const processed = [];
      return products.reduce(
        (acc,product)=>
          acc
          .then(_=>subscription.getAll(product._id))
          .then(subs=>update(subs, product))
          //add product id to processed product ids
          .then(_=>processed.push(product._id)),
        Promise.resolve()
      )
      //resolve with processed product id's
      .then(_=>processed)
      //when rejecting include the processed items
      .catch(err=>Promise.reject([err,processed]));
    }
    
    //using recursion
    const updateProducts = (products,processed=[]) =>
      (products.length!==0)
        ? subscription.getAll(products[0]._id)
          .then(subs=>update(subs, product))
          //add product id to processed
          .then(_=>processed.push(products[0]._id))
          //reject with error and id's of processed products
          .catch(err=>Promise.reject([err,processed]))
          .then(_=>updateProducts(products.slice(1),processed))
        : processed//resolve with array of processed product ids

    Aquí es cómo usted llamaría updateProducts:

    updateProducts(products)
    .then(processed=>console.log("Following products are updated.",processed))
    .catch(([err,processed])=>
      console.error(
        "something went wrong:",err,
        "following were processed until something went wrong:",
        processed
      )
    )

Dejar respuesta

Please enter your comment!
Please enter your name here