0

JavaScript では、オブジェクトの関数をオーバーライドしたいのですが、元の関数を呼び出してその値を返します。だから私は通常、次のようなことをします:

var render = res.render;

res.render = function() {
    doSomethingNew();
    return render.apply(this, arguments);
};

ただし、そのオーバーライドに、元の関数を呼び出す前に最初に起動する必要がある非同期コールバックが含まれている場合はどうでしょうか。

var render = res.render;

res.render = function() {
    var self = this;
    var args = arguments;

    var middlewares = getSomeMiddleware();

    return callNextMiddleware(middlewares, function() {
        return render.apply(self, args);
    });
};

function callNextMiddleware(middlewares, callback) {
    var middlewareFunc = middlewares.shift();

    if (middlewareFunc) {
        return middlewareFunc.call(function() {
            return callNextMiddleware(middlewares, callback);
        });
    }
    else {
        return callback();
    }
}

必要に応じて「return」ステートメントを使用していることに注意してください。ただし、「ミドルウェア」変数は関数の配列であり、各ミドルウェア関数は次のようになります。

function myMiddleware(next) {
    performLongRunningAsyncDataAccess(function() {
        next();
    });
}

「return next()」を使用しないため、元の res.render メソッドの戻り値が返されることはありません。すべてのミドルウェア関数で「return next()」を使用するようにすると、これを機能させることができますが、それらは外部ソースからのものであるため、それらを制御することはできません。「next()」を呼び出すことを保証することしかできません。 .

少し背景を説明すると、これは Node.js アプリです。ミドルウェアは基本的に Connect ミドルウェアで、Express.js の res.render メソッドをオーバーライドしようとしています。

4

2 に答える 2

2

return一般に、非同期関数とステートメントを混在させることはお勧めできません。返したいものはすべて、引数としてコールバック関数に渡すことができます。したがって、コードを正しく理解していることを願っていますが、関数を呼び出してrender関数の配列を取得すると仮定しますmiddleware。次に、次の関数を前の関数へのコールバックとして使用して、その配列内のすべての関数を実行します。すべての関数が実行された後、render関数を再度呼び出す必要があるため、一種の無限ループが作成されます。そのすべてを仮定して、あなたのreturn声明のいくつかを見てみましょう:

return middlewareFunc.call(function() {
    return callNextMiddleware(middlewares, callback);
});

このブロックの最初のものは非同期でreturnあるため役に立たないため、middlewareFuncおそらく が返されundefinedます。2 番目のreturnステートメントも、コールバックとして使用する関数から返されるため、役に立ちません。ただし、コールバックは を使用して呼び出されるだけなのでnext();、戻り値は使用されません。

else {
    return callback();
}

このブロックcallbackにはrender関数があります。それでは、この関数を見てみましょう。

res.render = function() {
    var self = this;
    var args = arguments;

    var middlewares = getSomeMiddleware();

    return callNextMiddleware(middlewares, function() {
        return render.apply(self, args);
    });
};

returnしたがって、関数から何かを返したいので、最後の 3 つのステートメントはすべて基本的にそこにありますrender。ただし、一貫性を保つために、その関数にもコールバックを使用することを検討する必要があります。

res.render = function(callback) {
    var self = this;
    var args = arguments;

    var middlewares = getSomeMiddleware();

    callNextMiddleware(middlewares, function() {
        //this will be called after all the middleware function have been executed
        callback();
        render.apply(self, args);
    });
};

したがって、基本的にはすべてのreturnステートメントを取り除き、純粋な非同期設計パターンを使用しています。

于 2013-07-29T09:07:16.367 に答える
1

callNextMiddlewareではなく、再帰呼び出しの戻り値を返す必要がありますmiddlewareFunc

if (middlewareFunc) {
    var result;
    middlewareFunc.call(this, function() {
        result = callNextMiddleware(middlewares, callback);
    });
    return result;
}

フィドル: http://jsfiddle.net/mWGXs

于 2013-07-29T08:27:24.820 に答える