node.js - can't catch Promise queue errors -
i'm setting node app have run series of asynchronous spawn tasks in order, i've got queue system set up. runs when reaches no errors. however, it's failing catch errors , log them when happen. here's right now:
function queue(tasks) { let index = 0; const runtask = (arg) => { if (index >= tasks.length) { return promise.resolve(arg); } return new promise((resolve, reject) => { tasks[index++](arg).then(arg => resolve(runtask(arg))).catch(reject); }); } return runtask(); } function customspawn(command, args) { return () => new promise((resolve, reject) => { const child = spawn(command, args, {windowsverbatimarguments: true}); child.on('close', code => { if (code === 0) { resolve(); } else { reject(); } }); }); }
the queue built , executed this:
myqueue.push(customspawn('cmd.exe', ['/c', convertpath, filelist[i], '-interlace', 'line', '-chop', croppixels, '-resize', '300', outfile])); queue(myqueue).then(([cmd, args]) => { console.log(cmd + ' finished - finished'); }).catch(function(error) { console.error(error.stack); });
the following error thrown: uncaught (in promise) typeerror: undefined not function(…)
sorry, can't quite understand queue
function refactored using array.prototype.reduce
. standard way chain things in compact way. following module models case , run in node. demonstrates how error handling works. assume want abort whole chain if there error?
'use strict'; const insp = require('util').inspect; const size = 10; const throwat = 6; var template = [1,2,3,4,5,6,7,8,9,]; var cmds = template.map((_, i) => ({cmd: `cmd ${_}`, args: [`arg1-${i}`, `arg2-${i}`]})); var queue = []; // promise factory function makepromise (command, args) { return () => new promise((resolve, reject) => { settimeout(_ => {if(command.indexof(throwat) > 0) { return reject(command); // whatever passed here hit catch } console.log(`${command}\t${insp(args)}`); resolve() }, math.random() * 1000) }) } // populate queue cmds.foreach(c => queue.push(makepromise(c.cmd, c.args))); // execute , catch errors queue.reduce((q, p) => q.then(p), promise.resolve()) .catch(e => console.log(`error: ${e}`));
you can add re-try logic this...
// promise factory function makepromise (command, args) { return () => new promise((resolve, reject) => { settimeout(_ => { if(command.indexof(throwat) > 0 && command.indexof('retry') === -1) { return makepromise(command + 'retry', args)() .then(_ => resolve(), e => reject(e)); } console.log(`${command}\t${insp(args)}`); resolve() }, math.random() * 1000) }) }
error propagation
playing around this, noticed error thrown inside a resolve
or reject
callback result in reject
of calling block being called, passing error object single argument. means error can thrown rather calling reject
. has benefit of delivering stack trace also.
managing cascade
by adding reject
callback each promise in chain, error propagation can managed if needed. if reject
calback added however, must re-throw error if needs propagated.
here implementation of these 2 principles...
function makepromise2 (command, args) { return (retry) => new promise((resolve, reject) => { if(retry){ console.log(`throw @ ${command}`); throw new error(`sorry, tried twice!`); } settimeout(_ => { if(command.indexof(throwat) > 0) { /* if(retry) // throwing here not handled throw new error(`sorry, tried best!`); */ return makepromise2(command, args)(true) .then(resolve, reject); // without fail silently } console.log(`${command}\t${insp(args)}`); resolve(); }, math.random() * 1000) }) } function reject (cmd) { return function reject (e) { console.log(`re-throw @ ${cmd.cmd}`); throw e; // if have reject callback must propagate error }} // populate queue cmds.foreach(c => queue.push(makepromise2(c.cmd, c.args))); // execute , catch errors // reject gives opportunity manage error cascade queue.reduce((q, p, i) => q.then(p, reject(cmds[i])), promise.resolve()) .catch(e => console.log(`catch...\n${e.stack}`));
Comments
Post a Comment