Estoy tratando de crear un efecto de rebote en una imagen después de una llamada sincrónica Y asincrónica, pero no puedo entender cómo hacerlo. El problema que tengo ahora es que a veces obtengo el efecto de rebote y luego isExecuted se vuelve verdadero porque el evento asincrónico lleva algún tiempo.

Mi código debería funcionar así:

Iterar sobre cada objeto en myEnum y ejecutar lo siguiente

  • si myCondition1 es igual también myCondition2 establece isExecuted = true
  • si lo anterior no es cierto, llame a un método asincrónico que evalúe algunas cosas, si es cierto establecerá isExecuted = true.
  • espere a que todo lo anterior haya terminado, luego, si isExecuted aún es falso, devuelva la imagen.

Aquí está el código:

var isExecuted = false;

myEnum.each() 
{
    if (myCondition1 == myCondition2) { //Synchronous 
        isExecuted = true;
        return false; //stop the iteration
    }   
    else {
        MyAsyncFunction(myCondition2, function(isTrue) { // Asynchronous
            if (isTrue) {
                isExecuted = true;
                return false; //stop the iteration
            }                   
        });
    }
});

// Execute this ONLY when above code is finished executing
if (isExecuted == false) {
    BounceImage();
}

Tenga en cuenta que la función asincrónica no siempre se ejecuta, pero la verificación de rebote siempre debe ejecutarse si isExecuted es verdadero.

-1
dadde 8 mar. 2017 a las 20:15

2 respuestas

La mejor respuesta

Toda esta configuración no funcionará como desea porque no puede detener la iteración de la devolución de llamada asincrónica. En su lugar, debe procesar la matriz (o lo que sea myEnum) de forma asincrónica y hacer algo después. Recomiendo aprender sobre promesas.

function process(array, cb) {
  var i = 0;
  
  function p(v) {
    return new Promise((resolve, reject) => {
      try {
        // call the callback, passing in the current value and 
        // a callback to control execution
        cb(v, function next(stop, result) {
          if (stop) {
            // if stop = true, abort the iteration and resolve the passed in value
            resolve(result);
          } else if (i < array.length) {
            // else if there are more elements left, process them
            resolve(p(array[i++]));
          } else {    // else resolve to the passed in value
            resolve(result);
          }
        });
      } catch(e) {
        reject(e);
      }
    });
  }
  
  // start with the first element
  return p(array[0]);
}

process([1,2,3], function(v, next) {
  if (v == 2) {
    return next(true, v);
  }
  next();
}).then(result => console.log(result));

Aplicado a su código se vería algo así

process(myEnum, function(v, next) {
  if (myCondition1 == myCondition2) {
    return next(true, true);
  } else {
    MyAsyncFunction(myCondition2, function(isTrue) {
      if (isTrue) {
        return next(true, true);
      }
      next();                 
    });
  }
}).then(function(isExecuted) {
  if (!isExecuted) {
    BounceImage();
  }
});

Por supuesto, también puede usar una biblioteca existente que le permita hacer esto. Hay muchas formas diferentes (potencialmente más elegantes) de lograr esto.

1
Felix Kling 8 mar. 2017 a las 17:56

En cambio, use devoluciones de llamada:

function asyncFunction (a, b, c, callback) {
  ...
  callback();
}

asyncFunction(1, 2, 3, function () {
  doSomethingOnceDone();
});

Esta es una práctica muy común. Es la forma en que la mayoría de los APIS de Chrome asíncronos lo hacen, solo por nombrar una cosa.

0
Domino 8 mar. 2017 a las 17:32