sincronas - recorrer array de objetos javascript
Cómo encadenar métodos asíncronos en las clases Javascript ES6 (4)
Quiero encadenar métodos de una clase. Tengo o problemas con los métodos sincrónicos, pero no sé cómo hacerlo con métodos asíncronos.
Por ejemplo, esta clase:
class Example {
constructor() {
this.val = 0
}
async () {
setTimeout(() => {
this.val += 1
return this
}, 5000)
}
sync () {
this.val += 1
return this
}
check () {
console.log(''checker'', this.val)
return this
}
}
Esto funciona:
new Example().sync().check()
> 1
Pero esto no funciona:
new Example().async().check()
> TypeError: Cannot read property ''check'' of undefined
PD. Quiero encadenar, no llamadas de recado del Infierno.
Lo que está buscando será resuelto de manera más elegante por Promises . Necesitarás probablemente instalar un polyfill, como Bluebird oq .
Cambiaría tu método asíncrono a:
async() {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
this.val += 1;
resolve(this);
}, 5000);
});
}
Y su código de llamada a:
new Example().async().then((instance)=>instance.check());
Desafortunadamente, hasta que las funciones de asincronización de ES7 estén definidas, no habrá una manera elegante de hacerlo sin alguna forma de devolución de llamada.
Si está utilizando funciones y métodos async
, está utilizando promesas (supongo que las conoce, si no, aprenda sobre ellas antes de seguir leyendo).
No debe usar setTimeout
dentro de una función asíncrona si considera esperarla. En su lugar, cree una promesa para el tiempo de espera, preferiblemente utilizando una función auxiliar como esta:
function timeout(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
});
}
Ahora puede escribir su método como realmente quisiera:
class Example {
…
async async () {
await timeout(5000);
this.val += 1;
return this;
}
…
}
Por supuesto, como función async
no devuelve la instancia en sí, sino una promesa para ella. Si va a encadenar, tendrá que llamarlo dentro de otra función asincrónica donde puede await
esa promesa:
(async function() {
(await (new Example().async())).check();
}());
Si todo lo que desea es un new Example().async().check()
para que funcione, todo lo que necesita hacer es return this
después de llamar a setTimeout. Ex:
async () {
setTimeout(() => {
this.val += 1
}, 5000)
return this
}
El return this
dentro del tiempo de espera no es necesario, ya que se ejecutará por sí mismo. Básicamente se está ejecutando solo en ese punto.
En realidad, si quieres que todo esto se ejecute de manera totalmente sincronizada y puedas controlar el flujo de cuando ocurren ciertas cosas, debes estar haciendo promesas para que eso ocurra.
Espero que quieras llamar a check()
vez que haya expirado el tiempo de espera. El problema es que se desvía, y no puede tener inmediatamente algo disponible para regresar.
Puede pasar check()
como devolución de llamada:
class Example {
constructor() {
this.val = 0
}
async (callback) {
setTimeout(() => {
this.val += 1
callback()
}, 5000)
}
sync () {
this.val += 1
return this
}
check () {
console.log(''checker'', this.val)
return this
}
}
// execution
var ex = new Example();
ex.async(ex.check)
... o una promesa
class Example {
constructor() {
this.val = 0
}
async (callback) {
var deferred = Q.defer()
setTimeout(() => {
this.val += 1
deferred.resolve();
}, 5000)
return deferred.promise;
}
sync () {
this.val += 1
return this
}
check () {
console.log(''checker'', this.val)
return this
}
}
// execution
var ex = new Example()
ex.async().then(() => ex.check())
... O podrías usar generadores ES6