3

node.js 中一个常用的异步函数调用习惯用法是这样使用回调函数:

library.doSomething(params, function(err,result) {
    if (err) {
        ... handle error, retry etc
    } else {
        ... process results, be happy!
    }
});

太好了 - 你调用一些东西,然后处理结果或错误。不幸的是,排除了第三个选项......您调用的代码永远不会执行您的回调。处理回调永远不会被调用的可能性的最佳方法是什么?

很多时候,特别是如果您正在编写一个依赖于网络的库,您需要保证您将调用一次且仅一次传递给您的任何回调。考虑到这一点,这样的模式看起来像是要走的路:

// set a timout
var failed = false, callbackFailure = setTimeout(function() {
    ... handle failure, call further pending callbacks with a timeout error
    failed = true;
},30000);

library.doSomething(params, function(err,result) {
    if (!failed) {
        clearTimeout(callbackFailure);
        if (err) {
            ... handle error, retry etc
        } else {
            ... process results, be happy again!
        }
    }
});

任何你期望触发的回调实际上都会触发,这似乎是一个信仰问题,我相信所有程序员都遇到过回调根本无法执行的场景——宇宙射线、太阳黑子、网络故障、错误第三方库,或者...喘不过气来...您自己的代码中的错误。

像我的代码示例这样的东西实际上是一个很好的实践,还是 node.js 社区已经找到了更好的方法来处理它?

4

2 回答 2

1

不看 paddle 似乎很容易为编写或调试错误的代码创建回调执行保险。

像这样的函数:

// requireCB:
//   timeout - milliseconds before insurance gets used
//   cb - callback function to invoke normally or when insurance expires
function requireCB(timeout, cb) {
    var timeoutTimer;
    var canBeCalled = false;
    var myCB = function () {
        if (timeoutTimer) { clearTimeout(timeoutTimer); timeoutTimer = 0; }
        if (canBeCalled) { canBeCalled = false; cb.apply(this, arguments); }
    };
    timeoutTimer = setTimeout(function () { myCB(new Error('timed out')) }, timeout);
    canBeCalled = true;
    return myCB;
}

我们创建可以像这样使用的保险小部件:

var rcb = requireCB(100, function (err, data1, data2) {
    console.log('called, err =', err, ', data1 =', data1, ', data2 =', data2);
});
functionExpectedToInvokeCallback(rcb);

或者在一个实际可立即运行的示例中:

var rcb = requireCB(100, function (err, data) {  // set insurance for 0.1 seconds
    console.log('called, err =', err, ', data =', data);
});
setTimeout(function () { rcb(undefined, 'sheep') }, 1000);  // set normal callback in 1 second

翻转超时值以不触发保险。

于 2012-10-05T09:52:12.180 回答
1

我不确定它去了哪里,但是这里突然出现了一个答案,并带有指向https://github.com/andyet/paddle的链接消失了- 一个旨在提供回调执行“保险”的小型库。至少它表明我不是第一个对这个问题挠头的人。

从文档中有一个轶事在一定程度上验证了这个问题:

众所周知,Node.js 有一个 http 客户端,但如果响应太快,有时 HTTP 请求不会发生回调。如果我想确保我的 http 客户端回调发生。

他们给出的示例比我的示例稍微复杂一些,并且可以处理基于事件的回调,使代码能够定期“签入”作为中间活动,如 ondata 处理程序触发,然后在停止或超时时触发错误。

setTimeout(function() {
    paddle.stop();
}, 12000);

var req = http.get(options, function(res) {
    var http_insurance = paddle.insure(function(res) {
        console.log("The request never had body events!");
        console.log('STATUS: ' + res.statusCode);
        console.log('HEADERS: ' + JSON.stringify(res.headers));
    }, 9, [res]);
    res.setEncoding('utf8');
    res.on('data', function (chunk) {
        console.log('BODY: ' + chunk);
        http_insurance.check_in();
    });
});
req.end();

我在这里回答我自己的问题,但我仍然有兴趣查看是否存在任何其他实现、库或模式来解决相同的问题。

于 2012-10-04T22:33:56.757 回答