Use cancel () dentro de una cadena creada por promisifyAll

No estoy seguro de ser lo suficientemente claro con este título, pero supongamos que tengo una clase llamada Foo con method1 , method2 y method3 . Prometo sus métodos con promisifyAll .

Luego tengo una cadena de “then” y quiero cancelar la operación a la mitad de la segunda o la primera, y no se debe llamar más.

Leí sobre Cancelación ( http://bluebirdjs.com/docs/api/cancellation.html ) pero no sé cómo implementarlo con promisifyAll.

El código que tengo más lo que necesito:

 var bluebird = require('bluebird'); function Foo() { } Foo.prototype.method1 = function (cb) {}; Foo.prototype.method2 = function (cb) {}; Foo.prototype.method3 = function (cb) {}; var foo = bluebird.promisifyAll(new Foo()); foo.method1Async() .then(function (r1) { // cancel then-chain res.json("Task stopped"); // just stop right here promises.cancel(); }) .then(function (r2) { console.log(r2); }).then(function (r3) { console.log(r3); }) .catch(function (er) { console.log('Catch!'); }); 

¿Cuál es la forma correcta de tener este resultado? Sé que solo puedo lanzar algo y atraparlo con el método de catch , pero esto haría un cambio muy grande en mi código real.

Intenta algo como esto:

 var bluebird = require('bluebird'); function Foo() { } Foo.prototype.method1 = function (cb) { cb(null, 'method1'); }; Foo.prototype.method2 = function (cb) { cb(null, 'method2'); }; Foo.prototype.method3 = function (cb) { cb(null, 'method3'); }; var foo = bluebird.promisifyAll(new Foo()); foo.method1Async() .then(function (r1) { console.log('step 1'); // cancel then-chain console.log("Task stopped"); // just stop right here return bluebird.reject('some reason'); }) .then(function (r2) { console.log('step 2'); console.log(r2); }).then(function (r3) { console.log('step 3'); console.log(r3); }) .catch(function (er) { console.log('Catch!'); console.log('Error:', er); }); 

En lugar de:

  return bluebird.reject('some reason'); 

puedes usar:

  throw 'some reason'; 

y el resultado sería el mismo pero no quiso cometer errores por lo que puede devolver una promesa rechazada.

Actualización 1

Pero si su intención es ejecutar los 3 métodos en serie, también deberá devolver la siguiente promesa en cada paso con algo como esto:

 var bluebird = require('bluebird'); function Foo() { } Foo.prototype.method1 = function (cb) { cb(null, 'method1'); }; Foo.prototype.method2 = function (cb) { cb(null, 'method2'); }; Foo.prototype.method3 = function (cb) { cb(null, 'method3'); }; var foo = bluebird.promisifyAll(new Foo()); foo.method1Async() .then(function (r1) { console.log('step 1'); console.log('got value:', r1); // cancel? change to true: var cancel = false; if (cancel) { console.log("Task stopped"); return bluebird.reject('some reason'); } else { console.log('Keep going'); return foo.method2Async(); } }) .then(function (r2) { console.log('step 2'); console.log('got value:', r2); return foo.method3Async(); }).then(function (r3) { console.log('step 3'); console.log('got value:', r3); }) .catch(function (er) { console.log('Catch!'); console.log('Error:', er); }); 

Actualmente, el código en su pregunta nunca ejecutaría ningún otro método que el primero.

Actualización 2

Otro ejemplo que no llama a la última catch para ese caso:

 foo.method1Async() .then(function (r1) { console.log('step 1'); console.log('got value:', r1); // cancel? change to true: var cancel = true; if (cancel) { console.log("Task stopped"); return bluebird.reject('some reason'); } else { console.log('Keep going'); return foo.method2Async(); } }) .then(function (r2) { console.log('step 2'); console.log('got value:', r2); return foo.method3Async(); }).then(function (r3) { console.log('step 3'); console.log('got value:', r3); }) .catch(function (er) { if (er === 'some reason') { return bluebird.resolve('ok'); } else { return bluebird.reject(er); } }) .catch(function (er) { console.log('Catch!'); console.log('Error:', er); }); 

Explicación

Piénsalo de esta manera: en código síncrono si tuvieras:

 r1 = fun1(); r2 = fun2(); r3 = fun3(); 

entonces la única manera para que fun1 cancele la ejecución de fun2 y fun3 sería lanzar una excepción. Y de manera similar para las promesas, la única forma en que un controlador podría cancelar la ejecución del siguiente controlador es devolver una promesa rechazada. Y al igual que con el código sincrónico, el bloque catch la excepción lanzada, aquí la promesa rechazada se pasaría al controlador catch .

Con el código síncrono puede tener un try/catch interno que atrapa la excepción y la vuelve a emitir si no es el específico que usó para cancelar su ejecución. Con las promesas puede tener un controlador de catch anterior que hace esencialmente lo mismo.

Esto es lo que sucede con el código en la Actualización 2. La razón de rechazo se compara con algún valor (que es 'some reason' en ese ejemplo) y si es igual, se devuelve una promesa resuelta y, por lo tanto, no se llama al siguiente controlador catch . Si no es igual, el motivo de rechazo se devuelve de nuevo como una promesa de rechazo que se pasa al siguiente controlador de catch como un error “real” que desea que maneje el último controlador de catch .