1

サービスへの HTTP 呼び出しを介して電話番号を保存するサイトがあり、サービスがページ上の電話番号にバインドするための電話番号エントリの新しい ID を返すとします。

この場合、電話は「telephones」という配列に格納され、datacontext.telephones.updateData は電話を $.Deferred([サービス コール ロジック]).promise(); 内のサーバーに送信します。

uploadTelephones = function (deffered) {
                for (var i = 0; i < telephones.length; i++){
                        deffered.push(datacontext.telephones.updateData(telephones[i], {
                            success: function (response) {
                                telephones[i].telephoneId = response;                                    
                            },
                            error: function () {
                                logger.error('Stuff errored');
                            }
                        }));                            
                 }
            }

今私が電話した場合:

function(){
    var deferreds = [];
    uploadTelephones(deferreds);
    $.when.apply($, deferreds)
                    .then(function () {
                        editing(false);
                        complete();
                    },
                    function () {
                        complete();
                    });
}

奇妙なことが起こります。すべての電話がサービスに返送され、保存されます。uploadTelephones メソッドの 'success' コールバックが 'response' として新しい ID で呼び出されると、クエリがどの電話に関連するかに関係なく、i の値は常に telephones.length+1 であり、回線は

telephones[i].telephoneId = response; 

telephones[i] が存在しないため、エラーがスローされます。

成功のコールバックで i の個々の値を保持する方法を教えてもらえますか?

4

1 に答える 1

3

すべてのクロージャー (ローカル スコープ内の変数をキャプチャする無名関数) は、同じインデックス変数を参照します。これは、telephones.lengthループ実行後の値になります。for必要なのは、ループを通過するたびに異なる変数を作成し、i作成のインスタンスでの値を後で使用できるように保存することです。

新しい別の変数を作成する最も簡単な方法は、ループ内の特定の場所で値をキャプチャしてすぐに実行するコードを使用して無名関数を作成することです。

これのいずれか:

for (var i = 0; i < telephones.length; i++)
{
    (function () {
        var saved = i;
        deffered.push(datacontext.telephones.updateData(telephones[saved],
        {
            success: function (response)
            {
                telephones[saved].telephoneId = response;
            },
            error: function ()
            {
                logger.error('Stuff errored ');
            }
        }));
    })();
}

またはこれ:

for (var i = 0; i < telephones.length; i++)
{
    (function (saved) {
        deffered.push(datacontext.telephones.updateData(telephones[saved],
        {
            success: function (response)
            {
                telephones[saved].telephoneId = response;
            },
            error: function ()
            {
                logger.error('Stuff errored ');
            }
        }));
    })(i);
}  

動作するはずです。

でも、それはちょっと醜いです。匿名関数を何度も実行するプロセスをすでに経験しているため、コードをもう少しきれいにしたい場合は、Array.forEachを見て、渡された引数をそのまま使用するか、jQuery.eachは、既に jQuery を使用しているためです。

于 2012-11-13T22:01:28.670 に答える