0

配列内にある一連の appId のループで sendMessage を呼び出しています。コールバックが呼び出されたら、エラーをチェックしてから、エラーのある appId を「ブラックリストに登録」する必要があります。問題は、これを試したすべての方法で、コールバックの appId が呼び出されるまでに変更されることです! したがって、間違った appId がブラックリストに登録されます。

私が試した3つのバージョンがあります(以下を参照)。1 つは決してブラックリストに登録せず、他の 2 つは間違ったものを実行します。

** この 1 つの黒は間違ったものをリストしています **

for ( var appName in apps )
{
    var app = apps[ appName ];

    var appId = app[ "appId" ];

    //Send message to that app
    chrome.runtime.sendMessage(
        app[ "appId" ],
        app,
        function (response)
        {
            var lastError = chrome.runtime.lastError;

            //Want to blacklist apps here
            if ( lastError && lastError.message.indexOf( "not exist" ) !== -1 )
            {
                //This blacklists the wrong one!
                myGlobalObject.addToTimeout( appId );
            }
        }
    );
}

**これもブラックリストに間違ったものがあります**

for ( var appName in apps )
{
    var app = apps[ appName ];

    var appId = app[ "appId" ];

    //Send message to that app
    chrome.runtime.sendMessage(
        app[ "appId" ],
        app,
        function (response)
        {
            var lastError = chrome.runtime.lastError;

            //Want to blacklist apps here
            if ( lastError && lastError.message.indexOf( "not exist" ) !== -1 )
            {
                //This blacklists the wrong one!
                myGlobalObject.addToTimeout( this[ "appId" ] );
            }
        }.bind( app )
    );
}

**これは決してブラックリストに載っていません**

for ( var appName in apps )
{
    var app = apps[ appName ];

    //Send message to that app
    chrome.runtime.sendMessage(
        app[ "appId" ],
        app,
        function (response)
        {
            var lastError = chrome.runtime.lastError;

            //Want to blacklist apps here
            if ( lastError && lastError.message.indexOf( "not exist" ) !== -1 )
            {
                //Somehow this NEVER blacklists it!
                myGlobalObject.addToTimeout( app[ "appId" ] );
            }
        }
    );
}
4

1 に答える 1

3

しばらくして呼び出されるコールバックの場合、クロージャーで変数の値を「凍結」する必要があります。これを行うにはいくつかの方法があります。ここでは、変数を引数として渡す即時呼び出し関数を使用する方法を示します。変数はその関数クロージャーでキャプチャされるため、コールバックの間、値が必要なままになります。

for ( var appName in apps )
{
    var app = apps[ appName ];

    var appId = app[ "appId" ];

    // this creates a closure which captures the values of your variables
    // and holds them at the desired value until the callback is called
    // a separate and unique closure will be created
    // for each cycle of the for loop
    (function(appID) {

        //Send message to that app
        chrome.runtime.sendMessage(
            appId,
            app,
            function (response)
            {
                // since this is called some time later
                // variables outside this may have different values
                // as the outer for loop continued to run
                var lastError = chrome.runtime.lastError;

                //Want to blacklist apps here
                if ( lastError && lastError.message.indexOf( "not exist" ) !== -1 )
                {
                    //This blacklists the wrong one!
                    myGlobalObject.addToTimeout( appId );
                }
            }
        );
    })(appID);
}
于 2013-06-11T22:45:09.890 に答える