• Empleos
  • Sobre nosotros
  • profesionales
    • Inicio
    • Empleos
    • Cursos y retos
  • empresas
    • Inicio
    • Publicar vacante
    • Nuestro proceso
    • Precios
    • Evaluaciones
    • Nómina
    • Blog
    • Comercial
    • Calculadora de salario

0

158
Vistas
Create a promise here, resolve it there

I thought I had the hang of promises in all situations, but I'm stuck here: I'd like an animation to happen on a timer. The only thing I can get from the graphics package is the frame number, so I compute an end frame based on a frame rate estimate.

The graphics package is p5.js, which exposes frameCount, that just runs up at about 60 fps on each draw cycle. (I named it currentFrame in this question, hoping that would clarify). As far as I can tell, this is the only visibility I get into the animation frame state in p5.js

doAnimation(duration) {
  // animation stuff
  this.endFrame = currentFrame + (60 * duration); // 60fps seems to be a good guess
}

draw() {
  if (currentFrame < this.endFrame) {
    // compute and draw the state of the animation
  } else if (currentFrame >= this.endFrame) {
    // animation done
  }
}

What I'm puzzled by is how to give the doAnimation caller a promise that resolves in the other method. I've tried this:

doAnimation(duration) {
  // animation stuff
  this.endFrame = currentFrame + (60 * duration);
  this.animationPromise = new Promise(resolve => {
    // I realize this is wrong, but it illustrates the problem. How do I run this test later?
    if (currentFrame >= this.endFrame) resolve();
  });
  return this.animationPromise;
}

draw() {
  if (currentFrame < this.endFrame) {
    // compute and draw the state of the animation
  } else if (currentFrame >= this.endFrame) {
    this.animationPromise.resolve();  // also wrong, I think
    // since resolve isn't an instance method of a promise
  }
}

Can somebody get me un-mixed up about this?

about 3 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

Instead of storing the promise to resolve, you need to store the resolver to call:

doAnimation(duration) {
  // animation stuff
  this.endFrame = currentFrame + (60 * duration);
  return new Promise(resolve => {
    this.onAnimationFinished = resolve;
  });
}

draw() {
  if (currentFrame < this.endFrame) {
    // compute and draw the state of the animation
  } else if (currentFrame >= this.endFrame) {
    this.onAnimationFinished();
  }
}

Of course you need to ensure that there is only one call to doAnimation() at a time, and that draw() is not called before doAnimation() (or more precisely, that onAnimationFinished is set up when an endFrame is set). You also might want to reset them (to undefined) once the end frame is reached.

about 3 years ago · Juan Pablo Isaza Denunciar

0

In general, fulfilling or rejecting a promise should be done by the process that was started within the executor function you passed new Promise. It's very rare to need to fulfill or reject the promise from outside it (at least, in a way that the caller realizes it's a promise fulfillment).

I'd use a callback queue:

  1. Maintain a list of pending animations which has the frame they end on and a callback.

  2. Have draw look through the queue for animation callbacks it should call based on the (new) currentFrame.

  3. Have the doAnimation code queue a callback

Roughly:

activeAnimations = [];

doAnimation(duration) {
    // animation stuff
    const endFrame = currentFrame + (60 * duration); // 60fps seems to be a good guess
    return new Promise(resolve => {
        this.activeAnimations.push({
            endFrame,
            done: resolve, // Or possibly: `done: () => resolve()`
                           // so this code is in control of whether
                           // there's a fulfillment value
        });
    });
}

draw() {
    for (let index = 0; index < this.activeAnimations; ++index) {
        const animation = this.activeAnimations[index];
        if (currentFrame > animation.endFrame) {
            // Animation done
            animation.done();
            this.activeAnimations.splice(index, 1);
            --index;
        } else {
            // Continue animation
        }
    }
}

The reason for the done: () => resolve() comment is that in general, I try to avoid directly exposing the promise resolve/reject functions to code outside the promise executor, on the basis that code outside it shouldn't typically be directly in control of what happens to the promise. (I make an exception for setTimeout. :-) ) But that may be overkill here.

about 3 years ago · Juan Pablo Isaza Denunciar

0

As an alternative, you can also assign to draw within the promise constructor callback:

function basicDraw() {
    // ...
}
var draw = basicDraw; // Default function

doAnimation(duration) {
    // animation stuff
    this.endFrame = currentFrame + (60 * duration);
    return new Promise((resolve) => {
        draw = () => {
            basicDraw();
            if (currentFrame < this.endFrame) {
                // compute and draw the state of the animation
            } else if (currentFrame >= this.endFrame) {
                draw = basicDraw; // back to normal
                resolve();
            }
        };
    });
}

doAnimation(1000).then(() => {
     /* whatever you want to do next */ 
});
about 3 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Nuestro proceso Comercial
Legal
Términos y condiciones Política de privacidad
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recomiéndame algunas ofertas
Necesito ayuda