angular - ¿Cuál es la forma adecuada de usar `.setTimeout()` en una cadena de Promesas?
En la aplicación que estoy construyendo, hay un caso de uso en el que necesito realizar una primera llamada a la API, esperar la respuesta y luego usar la información en la respuesta para realizar una segunda llamada a la API. Algo así:
firstAPI.call(some input)
.then(firstResponse => {
return secondAPI.call(firstResponse);
})
.then((secondResponse) => {
//do something
})
.catch(error => {
console.error(error);
});
Todos estos funcionaron bien. Sin embargo, actualmente, por alguna razón, la segunda llamada a la API no se puede realizar inmediatamente después de la primera, y debe haber algún intervalo antes de que pueda funcionar. Luego intenté usar .setTimeout() así:
firstAPI.call(some input)
.then(firstResponse => {
//save the response somewhere
})
.then(() => {
// Wait 1.5s before calling the second API
return this.sleep(1500);
})
.then(() => {
return secondAPI.call(saved first response);
})
.then((secondResponse) => {
//do something
})
.catch(error => {
console.error(error);
});
private sleep(milliseconds: number): Promise<Object> {
return new Promise(resolve => {
setTimeout(resolve, milliseconds)
});
}
Y probé este fragmento de código para los siguientes escenarios:
1) Tanto la primera como la segunda llamada tuvieron éxito - funcionó bien y durmió durante 1,5 s;
2) La primera llamada falla - funcionó bien con el error siendo capturado;
3) La primera llamada tuvo éxito pero la segunda falla - ¡no funcionó; el error no fue capturado! El fragmento de código de prueba unitaria es el siguiente:
describe('when first call succeeds but second call fails', () => {
it('should log errorMsg', fakeAsync(() => {
let mockFirstResponse: Promise<Object> = Promise.resolve(some mock response);
spyOn(firstAPI, 'call').and.returnValue(mockFirstResponse);
spyOn(secondAPI, 'call').and.returnValue(Promise.reject(new Error('Oops!')));
spyOn(console, 'error').and.callThrough();
underTest.submit(); // Call my function
tick(1500);
expect(console.error).toHaveBeenCalled();
}));
});
La prueba unitaria falló con error:
Error: No capturado (en promesa): Error: ¡Vaya! en resolvePromise (webpack:///~/zone.js/dist/zone.js:469:0 <- configuration/karma/karma-entry.js:128867) en webpack:///~/zone.js/dist/zone.js:528:0 <- configuration/karma/karma-entry.js:128926
El bloque .catch no se ejecutó en absoluto.
Mi hipótesis es que .setTimeout() rompe la cadena de alguna manera. ¿Cuál es la forma preferida de hacer esto?
Respuesta #1
Aprecio que tu código esté haciendo algo muy similar, pero prueba esto.
Introduce una nueva promesa en la cadena que no haga nada más que retrasar la ejecución del siguiente bloque en la cadena de la siguiente manera:
firstAPI.call(someinput)
.then(firstResponse => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(firstResponse);
}, 1500)
})
})
.then(firstResponse => {
return secondAPI.call(firstResponse);
})
.then((secondResponse) => {
// do something
})
.catch(error => {
console.error(error);
});
Por una suposición total, la razón de la necesidad de la demora puede deberse al servidor, que después de responder, realiza algún procesamiento que lleva uno o dos segundos completar o tal vez esté reindexando o haciendo algún truco raro.
