3

node.js で頻繁に使用される非同期関数呼び出しのイディオムは、次のようなコールバック関数を使用することです。

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

これは素晴らしいことです。何かを呼び出してから、後で結果またはエラーを処理します。残念ながら、除外された 3 番目のオプションがあります...呼び出したコードがコールバックを実行しないというものです。コールバックが呼び出されない可能性を処理する最善の方法は何ですか?

多くの場合、特にネットワークに依存するライブラリを作成している場合は、渡されたコールバックを一度だけ呼び出すことを保証する必要があります。それを念頭に置いて、次のようなパターンが進むべき道のように見えます。

// 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

どこに行ったのかはわかりませんが、ここに答えが表示され、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 に答える
1

パドルを見ていなくても、不適切に記述またはデバッグされたコードに対してコールバック実行保証を作成するのは簡単に思えます。

このような関数:

// 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 に答える