2016-08-04 23 views
2

Ich versuche, über ein Array zu iterieren und eine Variable mit einer for-Schleife zuzuweisen. So etwas wie das:

function Person(name, status){ 
    this.name = name; 
    this.status = status; 
} 

var status = []; 
var array = ["bill","bob","carl","ton"]; 
function exAjax(function(){ 
for(var i = 0; i < array.length; i++){ 
    var name = array[i]; 
    console.log(name); =====> this gives the correct name 

    $.ajax({ 
    url: xxxxxxx, 
    success: function(data){ 
     if(data.stream === null){ 
     var person = new Person(name, "dead"); 
     console.log(name); =====> return undefined until the last 
     person 

     status.push(person);  
     } 
    } 

    }) 
    name = ""; 
} 
}) 

Das Problem, das ich habe, ist, dass der Name nicht in die Erfolgsfunktion kommt. Ich dachte, js fährt weiter nach oben, um nach der Variable zu suchen, wenn sie nicht in ihrem aktuellen Umfang existiert? Ich bekomme undefiniert für die Variable name, wenn ich versuche, console.log name! Scope beherrscht was mache ich falsch?

+1

AJAX ist asynchron. Zu dem Zeitpunkt, zu dem die 'success'-Funktion ausgeführt wird, ist die for-Schleife bereits beendet. Was denkst du, ist der Wert "i" nachdem die Schleife beendet ist? – Xufox

+0

Mögliches Duplikat von [JavaScript closure in loops - einfaches praktisches Beispiel] (http: // stackoverflow.com/questions/750486/javascript-closure-inside-loops-einfach-praktisch-beispiel) – Xufox

+0

Vielen Dank! Wenn ich async setze: "false"; Für diesen Ajax-Aufruf wird das das Problem beheben? – powerup7

Antwort

4

können Sie .queue(), $.map() verwenden Umfang name zu halten. Ändern Sie außerdem das Array status in ein Objekt mit der Eigenschaft status, wobei Wert ein Array ist, um einen möglichen Konflikt mit this.status des Objekts Person zu vermeiden.

Hinweis, können Sie auch .promise(/* queueName */) Kette an .then() Aufgaben auszuführen, wenn alle Funktionen in queueName Warteschlange, i.e.g., "status" berufen worden, queueName.length ist 0.

function Person(name, status){ 
 
    this.name = name; 
 
    this.status = status; 
 
} 
 

 
var blob = new Blob(['{"stream":null}'], {type:"application/json"}); 
 
var url = URL.createObjectURL(blob); 
 
// change `status` array reference, e.g., to `arr` 
 
var arr = {status:[]}; 
 
var array = ["bill","bob","carl","ton"]; 
 

 
$(arr).queue("status", $.map(array, function(curr) { 
 
    return function(next) { 
 
    var name = curr; 
 
    // do asynchronous stuff 
 
    $.ajax({url:url, dataType:"json"}) 
 
    .then(function(data) { 
 
     if(data.stream == null){ 
 
     var person = new Person(name, "dead"); 
 
     console.log(name, person); 
 
     arr.status.push(person); 
 
     } 
 
    }) 
 
    .then(next) // call next function in `"status"` queue 
 
    } 
 
})) 
 
.dequeue("status") 
 
.promise("status") 
 
// do stuff when all functions in `"status"` queue have completed, 
 
// `"status"` queue `.length` is `0` 
 
.then(function() { 
 
    // `this` : `arr` as jQuery object 
 
    // `this[0].status`: array containing objects pushed to `arr.status` 
 
    console.log(this[0].status); // $(this).prop("status"); 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> 
 
</script>

jsfiddle https://jsfiddle.net/nnayjckc/2/


Sie können alternativ verwenden $.when(), .apply(), $.map(), das gleiche Resultat

function Person(name, status) { 
 
    this.name = name; 
 
    this.status = status; 
 
} 
 

 
var blob = new Blob(['{"stream":null}'], { 
 
    type: "application/json" 
 
}); 
 
var url = URL.createObjectURL(blob); 
 
// change `status` array reference, e.g., to `arr` 
 
var arr = { 
 
    status: [] 
 
}; 
 
var array = ["bill", "bob", "carl", "ton"]; 
 

 
$.when.apply($, $.map(array, function(curr) { 
 
    var name = curr; 
 
    return $.ajax({ 
 
     url: url, 
 
     dataType: "json" 
 
    }) 
 
    .then(function(data) { 
 
     if (data.stream == null) { 
 
     var person = new Person(name, "dead"); 
 
     console.log(name, person); 
 
     arr.status.push(person); 
 
     } 
 
    }) 
 
})) 
 
.then(function() { 
 
    console.log(arr.status) 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> 
 
</script>
zurückzukehren

jsfiddle https://jsfiddle.net/nnayjckc/3/

+0

Vielen Dank für die gründliche Erklärung. Ich schätze es! – powerup7

0

Das ist, weil $.ajax eine asynchrone HTTP (Ajax) Anfrage durchführen. Dies bedeutet, dass Ihre for-Schleife nicht auf success wartet. Stattdessen wird es mit seiner Iteration fortfahren.

Eine Möglichkeit (von vielen möglichen Lösungen), dann ist dies $.ajaxsynchronous mit der async: false Option machen

Vom documentation

async (Standard: true)
Typ: Boolean
Standardmäßig sind alle Anforderungen wird asynchron gesendet (d. H. Dies ist standardmäßig auf true eingestellt). Wenn Sie synchrone Anforderungen benötigen, legen Sie diese Option auf false fest.

for(var i = 0; i < array.length; i++){ 
    var name = array[i]; 
    console.log(name); =====> this gives the correct name 

    $.ajax({ 
    url: xxxxxxx, 
    async: false, 
    success: function(data){ 
     if(data.stream === null){ 
     var person = new Person(name, "dead"); 
     console.log(name); =====> return undefined until the last 
     person 

     status.push(person);  
     } 
    } 

    }) 
    name = ""; 
} 
})