Nodejs中如何处理一个函数下多次回调的风险

How to handle risk of multiple callbacks under one function in Nodejs

我正在使用async.map处理多个任务,我想为每个任务设置一个超时时间。

async.map(tasks, handleFunction, (error, callback))

I add the setTimeout inside handleFunction to return immediately,

const handleFunction = function(callback){

setTimeout(()=> {return setImmediate(callback, new Error())});

// handler logic, detail process code ...
// some http requests or file read and 

return callback();
}

以上,return调用多个回调是有风险的,一个来自正常流程代码(如果任务成功完成),一个来自setTimeout。

我的问题是:有没有更好的方法来避免这种情况。导致目前解决方案可能return两次回调。我收到以下错误:"Callback was already called."

你可以只设置一个标志来判断你是否已经调用了回调。您可以将其放入 async.map() 处理程序中:

let called = false;
function doCallback(err, data) {
   if (!called) {
       called = true;
       callback(err, data);
   }
}

然后,在您的 async.map() 处理程序中使用 doCallback() 而不是 callback()。如果你多次调用 doCallback(),它什么都不做。只有对其的第一次调用才会传递到实际的异步回调。


如果您展示了包含所有详细信息的实际代码,我们还可以建议一种编码方法,如果您在定时器关闭之前调用回调并且定时器确实触发,则在定时器触发之前取消定时器,然后设置一个您已经超时的标志,以便您可以在事情完成后调用 callback() 之前检查该标志。


您也可以自己制作一个回调超时实用程序函数,您可以在需要此类功能的任何地方重新使用它。

// callback that times out
function timerCallback(t, timeoutErr, callback) {
    let called = false;
    let timer = setTimeout(() => {
        if (!called) {
            called = true;
            callback(timeoutErr);
        }
    }, t);
    return function(err, data) {
        clearTimeout(timer);
        if (!called) {
            called = true;
            callback(err, data);
        }
    };
}

然后您将像这样使用它:

async.map(tasks, handleFunction, (error, callback))

    // create callback with debouncing and timeout
    let internalCallback = timerCallback(1000, new Error("timeout"), callback);

    // then do your async stuff and call internalCallback(err, data) when done
 }