2016-04-19 8 views
1

Ich versuche einen Viewer zu erstellen, der twitch.tv api verwendet, um ein Array von Twitch-Streamern zu überprüfen und dann zu veröffentlichen, welche Benutzer gerade online sind und was sie streamen. Ich habe einige ernsthafte Probleme herauszufinden, wie man mit der asynchronen Art von Callbacks arbeitet.Wie kann ich warten, bis asynchrone Rückrufe beendet sind, bevor die abgerufenen Daten verwendet werden?

Ich möchte den API-Aufruf einmal für jeden Twitch-Benutzer im Array Schleife. NACHDEM sie alle zurückgekehrt sind, möchte ich in der Lage sein, sie zu sortieren und sie nach bestimmten Kriterien aufzulisten.

Nach viel Forschung versuche ich, Versprechungen zu tun, dies zu tun. Aber ich komme immer noch nicht dazu, das herauszufinden.

Ich habe diese Frage verwendet: How can I wait for set of asynchronous callback functions? und diese Frage: How do I return the response from an asynchronous call? als Richtlinie aber offensichtlich fehlt mir noch etwas Wichtiges. Ich habe den relevanten Teil meines Codes veröffentlicht. Ich würde jede Hilfe/jeden Stoß in die richtige Richtung zu dem, was mir fehlt, schätzen.

$(document).ready(function() { 
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff","ESL_SC2", "brunofin"]; 
var test = []; 
function getData(){ 
    var promises = []; 
    for (var i = 0; i < channels.length; i++) { 
     promises.push($.getJSON('https://api.twitch.tv/kraken/streams/'+channels[i]+'?callback=?', function(data) {})); 
    } 
    $.when.apply($, promises).then(function() { 
     // returned data is in arguments[0][0], arguments[1][0], ... arguments[9][0] 
     // you can process it here 
     for(var j=0; j<promises.length; j++){ 
      //console.log(promises[j].responseJSON); 
      test.push(promises[j]); 
     } 
    }, function() { 
     // error occurred 
     conole.log("get data error"); 
    }); 
} 

    getData(); 
    console.log("do I have data?: "); 
    for(var j=0; j<test.length; j++){ 
      console.log(test[j].responseJSON); //This is empty and where I need the data! 
     } 

});

+0

Sie sollten 'return' die' $ .when.apply ($, Versprechen) 'von Ihrer Funktion und dann' 'setzen .then (...) nach dem' getData() 'nennen – Bergi

Antwort

2

In Ihrem Code rufen Sie getData() und dann in der nächsten Zeile iterieren Sie über die test Array. Dies geschieht im selben Durchlauf der Ereignisschleife, so dass Sie Ihren Versprechungen keine Chance geben, ihre Logik tatsächlich auszuführen und zu irgendetwas zu lösen. Die zeilenweise Ausführung ist synchron und es können keine Operationen dazwischen ausgeführt werden.

Eine Lösung besteht darin, ein Versprechen aus der getData-Funktion zurückzugeben und darauf zu warten, dass es aufgelöst wird.

Da Sie mit Promises arbeiten, benötigen Sie auch keinen Rückruf an die $getJSON-Funktion.

$(document).ready(function() { 
    var channels = [ 
    "freecodecamp", "storbeck", "terakilobyte", "habathcx", 
    "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff", 
    "ESL_SC2", "brunofin" 
    ]; 

    var test = []; 

    function getData() { 
    var promises = []; 
    for (var i = 0; i < channels.length; i++) { 
     promises.push(
     $.getJSON(
      'https://api.twitch.tv/kraken/streams/'+channels[i]+'?callback=?' 
     ) 
    ); 
    } 

    return $.when.apply($, promises).then(function() { 
     for(var j=0; j<promises.length; j++){ 
     test.push(promises[j]); 
     } 
    }); 
    } 

    getData().then(function() { 
    console.log("do I have data?: "); 
    for(var j=0; j<test.length; j++) { 
     console.log(test[j].responseJSON); 
    } 
    }); 
}); 

Lassen Sie mich auch darauf hin, ein Refactoring dieses Codes. Dies ist eine interessante und in JavaScript übliche Aufgabe und ich möchte anhand dieses Beispiels demonstrieren, wie man mit Arrays von Versprechen arbeitet.

Jeder asynchrone Betrieb läuft unabhängig und Ihr Instinkt war korrekt: Sie benötigen ein zusätzliches Werkzeug, um alle Ergebnisse zusammenzuführen.

Wenn Versprechungen verwendet werden, ist dieses Tool Promise.all. In der Tat ist $.when von jQuery ähnlich, obwohl ich Promise.all einfacher finde, mit wegen seiner Eingänge und Rückkehrarten zu arbeiten. Es ist auch Standard-JavaScript und ist in allen modernen Browsern verfügbar.

Promise.all kann verwendet werden, um einige Logik zu laufen, wenn eine Reihe von einzelnen Versprechen zu lösen. Formal akzeptiert Promise.all eine Reihe von Versprechen und gibt ein einzelnes Versprechen zurück, das löst, wenn alle Eingabeversprechen aufgelöst werden (oder einer von ihnen ablehnt). Es löst ein Array aufgelöster Werte auf, in die sich einzelne Versprechen aufgelöst haben.

Da Promise.all ein Array verwendet, funktioniert es hervorragend mit Array-Methoden wie map und filter.

function getStreams(channels) { 
    // Transform an array of channel names into an array of Promises 
    // representing the asynchronous action of getting the info 
    // about each channel. 
    const promises = channels.map(
    channel => $.getJSON(
     'https://api.twitch.tv/kraken/streams/'+channel+'?callback=?' 
    ) 
); 

    // Return a new promise which will resolve when *all* channels 
    // have been queried. 
    return Promise.all(promises); 
} 

const channels = [ 
    "freecodecamp", "storbeck", "terakilobyte", "habathcx", 
    "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff", 
    "ESL_SC2", "brunofin" 
]; 

getStreams(channels).then(
    // infos is an array of resolved data about the channels 
    infos => infos.forEach(
    info => console.log(info) 
) 
); 
+0

Das ist perfekt. Es ist so viel sauberer und lesbarer als zu versuchen, alles in eine riesige Funktion zu bringen. – MichelleJS

0

Asynchron ist genau das, was der Name impliziert.

Sie können auf diese Daten nur in der ersten Funktion der Wenn-Rückrufe zugreifen. aufgrund der Tatsache, dass die Daten bis dahin auf Ihrer Seite nicht existieren.

+0

Ich verstehe dass ich vorher nicht auf die Daten zugreifen kann. Ich möchte die Daten speichern und anschließend darauf zugreifen. – MichelleJS

+0

Ja. So können Sie im Rückruf auf es zugreifen. – Tuvia

Verwandte Themen