2

オブジェクトの配列を作成し、配列内のオブジェクト プロパティにアクセスしようとしていますが、未定義のまま返されます。createObjArray() 関数を呼び出し、console.log(objArray[1]); を実行した直後に そして、オブジェクトをすべてのプロパティとともに印刷します。ただし、console.log(objArray[1].name); を実行しようとすると、firebug は「未定義」を出力します。また、firebug でコードをステップ実行するときに、objArray[1].name にマウスを合わせると、正しい名前が表示されます。ここで何が起こっているのか、気が狂いそうです。

var objArray = [];

function createObjectArray(numOfObjs) {

    for(var i=0; i<numOfObjs; i++) {

packages.push(initObj(i)); 

    }
 }

function initObj(i){
    var newPackage;
    var p = {};
    $.getJSON('.../package' + i + '.json', function(data) {
        newPackage = new Package(data);
        p.name = newPackage.name;
        p.id = i;      
    });
    return p;
 }
4

2 に答える 2

1

これは機能します:

var objArray = [];

function createObjectArray(numOfObjs, callback) {
    var filledPackage = [];
    var nbLeft = numOfObjs;
    for(var i=0; i<numOfObjs; i++) {
        initObj(i, function(p){
            filledPackage.push(p);
            nbLeft--;
            if (nbLeft === 0){
                callback(filledPackage);
            }
        }); 
    }
 }

function initObj(i, callback){
    var newPackage;
    var p = {};
    $.getJSON('.../package' + i + '.json', function(data) {
        newPackage = new Package(data);
        p.name = newPackage.name;
        p.id = i;     
        callback(p);
    });
}

//Get a filled object array:
createObjectArray(5, function(filledArray){
    objArray = filledArray;
    //Code here will be executed AFTER all the $.getJSON queries have returned.
    //objArray is not empty.
});
//Code here will be executed WHILE the getJSON queries are running and
//while objArray is still empty. Due to the way the JS event loop works,
//it is impossible that code placed here will be able to use the content
//of objArray unless you call an async function such as anything AJAX or
//setTimeout, but that's iffy. Code you want to be executed once objArray
//has been filled should be inside of the callback above.

問題は、$。getJSONが非同期であるということです。つまり、結果が自動的に返されません。代わりに、コールバックを提供します。コールバックは、結果を受け取った後に実行する関数です。この場合、コールバックは$.getJSONを呼び出すときに作成される無名関数です。そのコールバックはサーバーから結果を受け取り、それを配列に追加してから、配列がいっぱいになっているかどうかを確認します。$ .getJSON関数のために非同期コードを実行しているため、結果も非同期で返す必要があります。そのためには、initObj関数が完了したら呼び出す関数(別のコールバック)を受け取るように要求します。そのコールバックを呼び出して、パラメーターを渡します。次に、塗りつぶされた配列をコールバックを介してもう一度返します。

于 2012-11-07T00:33:06.733 に答える
0

$.getJSON への呼び出しは非同期です。initObj() が p を返すとき、それはまだ空のオブジェクトです。

ただし、initObj() は p への参照をキャプチャするクロージャーを作成するため、$.getJSON が返されると p が入力されます。

これが、配列を作成した直後に実行するコードでオブジェクトが空に見える理由です。ただし、コンソール コマンドを実行するまでに、非同期呼び出しが返され、オブジェクトが設定されます。

アレイでの作業を続行する前に、すべての非同期呼び出しが戻るのを待つ必要があります。これを行う 1 つの方法は、呼び出しを行ったときにカウンターをインクリメントし、呼び出しが返されたときにカウンターをデクリメントし、最後の呼び出しが返されたときにカウンターがゼロになり、処理を続行することです。

または、setTimout ループを設定して、すべての項目が入力されたときに配列のチェックをポーリングし続けることもできます。

いずれかの呼び出しが失敗する可能性があると思われる場合、どちらのアプローチも危険ですが、複数の ajax 呼び出しを行っているため、複数の可能性のある失敗を処理する必要があるため、アプローチ自体は根本的に危険です。jQuery.ajax の成功/エラー ハンドラーで成功/エラー状態を一度に処理できるように、すべてのデータを一度に取得する方がはるかにクリーンです。

于 2012-11-06T23:31:54.103 に答える