1

非同期プログラミングを機能させる方法に頭を悩ませようとしています。

私の現在のユースケースでは、1 秒間に複数回呼び出される可能性のある関数があり、関数間で変化する可能性のある複数の変数に依存するコールバックがあります。

簡単な例: (簡潔にするために coffeescript を使用)

doSomething = (requestor, thing, action, callback) ->
  thing.takeAction action, (result) ->
    # actually a lot of times this nests down even further
    requestor.report result
    callback result

thing.takeAction が結果を返す前に doSomething が異なるデータで複数回呼び出された場合、リクエスターとコールバックが必要なものと同じであることを信頼できないと思います。正しい?

これを回避するには、requestor と callback を takeAction の callback に挿入する必要があります。それはどういうわけか可能ですか?

私は次のようなことをするという考えを得ました

doSomething = (requestor, thing, action, callback) ->
  thing.takeAction action, (result, _requestor = requestor, _callback = callback) ->
    _requestor.report result
    _callback result

しかしもちろん、これは単なる CoffeeScript のハックであり、まったく機能しません。


ところで、私は caolan/async モジュールを使用してこれを支援しようとしていましたが、async が提供できるよりも多くの変数がコールバックで必要になることが多いという事実は依然として残っています。お気に入り:

doSomething = function(requestor, thing, action, callback) {
  // this might not need a waterfall, but imagine it would have nested further

  async.waterfall(
  [
    function(next) {
      thing.takeAction(action, function(result) {
        // How can I know that action is still the same?
        next(null, result);
      });
    }, 
    function(result, next) {
      requestor.report(result); // requestor still the same?
      next(null, result);
    }
  ],

  function(err, result) {
    callback(result); // callback still the same?
  });
}

それでも同じ問題が残ります。では、これを行うにはどうすればよいですか?

お時間をいただきありがとうございます。

4

2 に答える 2

2

actionオブジェクトのコンテンツをaction値自体から分離する必要があります。つまりaction、この特定のコンテキストで名前によって参照されるオブジェクトがメモリ内にあるということです。

例えば、

function test(action) {
    alert("Test1: " + action.value);
    setTimeout(function () { alert("Test2: " + action.value); }, 1000);
}

var action = { value: 1; };
test(action);
action = { value: 2 };
alert("Action value outside: " + action.value);

「Test1: 1」、「Action value outside: 2」、および「Test1: 1」をアラートします。ただし、 に置き換えるaction = { value: 2 };action.value = 2、最後のアラートは「Test1: 2」に変更されます。

したがって、アクション オブジェクトの一部のフィールドが外部で変更されることが問題である場合は、doSomething の最初の行でそれを複製するだけです。オブジェクトへの参照が外部で変更されていることが問題である場合、心配する必要はありません。影響はありませんdoSomething

さらに、doSomething への後続の呼び出しは、特定の呼び出しで閉じられるため、コールバックのアクション パラメーターの値を「オーバーライド」しません: en.wikipedia.org/wiki/Closure_(computer_science)

例えば、

function test(action) {
    alert("Test1: " + action.value);
    setTimeout(function () { alert("Test2: " + action.value); }, 1000);
}

var action = { value: 1; };
test(action);
action = { value: 2 };
test(action);

「Test1: 1」、「Test1: 2」、「Test2: 1」、および「Test2: 2」をアラートします (「Test1: 1」、「Test1: 2」、「Test2: 2」、および「Test2: 2」ではありません)。あなたが恐れているようです)。

于 2012-08-17T09:54:12.193 に答える
1

CSを使用することがこの例に本当に役立つかどうかはわかりませんが、単純なJSで説明します。

var doSomething = function (requestor, thing, action, callback) {
    thing.takeAction(action, function (result) {
        requestor.report(result);
        callback(result);
    });
};

// Following is completely safe:
doSomething(r1, t1, a1, c1); 
doSomething(r2, t2, a2, c2); 
doSomething(r3, t3, a3, c3); 

doSomethingが呼び出されるたびに、新しい関数スコープが作成されます。したがって、内部的には、作成されてtakeActionに渡される関数は、最初にdoSomethingが呼び出された引数にアクセスできます(doSomethingをもう一度呼び出しても変更されません!)。これがJavaScriptでのスコープの仕組みです

于 2012-08-17T11:23:03.193 に答える