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

时间:2018-01-05 21:02:16

标签: javascript node.js callback settimeout async.js

我使用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();
}

上面,返回多个回调的风险很大,一个来自正常的流程代码(如果任务成功完成),一个来自setTimeout。

我的问题是:有没有更好的方法来避免这种情况。导致当前解决方案可能会返回两个回调。我收到了以下错误:"已经调用了回调。"

1 个答案:

答案 0 :(得分:1)

您可以设置一个标志,表明您是否已经调用了回调。你可以将它放在你的async.map()处理程序中:

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

然后,在doCallback()处理程序中使用async.map()而不是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
 }