我正在设置一个节点应用程序,我必须按顺序运行一系列异步生成任务,所以我已经建立了一个队列系统。它在没有错误时运行良好。但是,它没有捕获错误并在它们发生时记录它们。这就是我现在的位置:
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();
}
});
});
}
队列的构建和执行方式如下:
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 - all finished');
}).catch(function(error) {
console.error(error.stack);
});
抛出以下错误:
Uncaught (in promise) TypeError: undefined is not a function(…)
答案 0 :(得分:1)
抱歉,我无法理解您的queue
功能,因此我使用Array.prototype.reduce
重构了它。这是以紧凑的方式链接事物的标准方法。以下模块为您的案例建模并将在节点中运行。它演示了错误处理的工作原理。如果出现错误,我假设您要中止整个链?
'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 is passed here will hit the catch
}
console.log(`${command}\t${insp(args)}`);
resolve()
}, Math.random() * 1000)
})
}
// populate the queue
cmds.forEach(c => queue.push(makePromise(c.cmd, c.args)));
// then execute it and catch all errors
queue.reduce((q, p) => q.then(p), Promise.resolve())
.catch(e => console.log(`error: ${e}`));
你也可以像这样添加一些重试逻辑......
// 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)
})
}
玩弄这个,我注意到在resolve
或reject
回调中抛出的任何错误都会导致调用调用块的reject
,将错误对象传递为单一的论点。这意味着可以抛出错误,而不仅仅是调用reject
。这也有提供堆栈跟踪的好处。
通过向链中的每个promise添加reject
回调,可以根据需要管理错误传播。但是,如果添加了reject
calback,则必须在需要传播时重新抛出错误。
以下是这两个原则的实现......
function makePromise2 (command, args) {
return (retry) => new Promise((resolve, reject) => {
if(retry){
console.log(`throw at ${command}`);
throw new Error(`sorry, tried twice!`);
}
setTimeout(_ => {
if(command.indexOf(throwAt) > 0) {
/*
if(retry) // throwing here will not be handled
throw new Error(`sorry, tried my best!`);
*/
return makePromise2(command, args)(true)
.then(resolve, reject); // without this it will fail silently
}
console.log(`${command}\t${insp(args)}`);
resolve();
}, Math.random() * 1000)
})
}
function Reject (cmd) {
return function reject (e) {
console.log(`re-throw at ${cmd.cmd}`);
throw e; // if you have a reject callback then you must propagate the error
}}
// populate the queue
cmds.forEach(c => queue.push(makePromise2(c.cmd, c.args)));
// then execute it and catch all errors
// the Reject gives the opportunity to manage the error cascade
queue.reduce((q, p, i) => q.then(p, Reject(cmds[i])), Promise.resolve())
.catch(e => console.log(`catch...\n${e.stack}`));