2010-02-08 10 views
7

Ich möchte eine asynchrone Funktion auf die synchrone zu schalten.Asynchrone Programmierung in JavaScript ohne unordentliche Rückrufe

function fetch() { 
    var result = 'snap!'; 
    $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function messyCallback(data){ 
    result = data; 
    }); 
    return result; 
} 

document.write(fetch());​

See in action

Das Ergebnis wird es immer sein 'Snap!', Weil $.getJSON Lauf nach fetch() erfolgt.

Meine erste Idee war:

function fetch() { 
    var result = 'snap!'; 
    $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function messyCallback(data){ 
    result = data; 
    }); 
    while (true) { if (result != 'snap!') return result; } 
}

Es ist nicht und auch den Browser abblasen funktioniert.

Ich lese über generators and iterators in JS 1.7, aber ich habe keine Ahnung, wie man es auf mein Problem anwenden.

Diese Frage ist nicht wirklich über jQuery. Anstelle von $.getJSON könnte irgendeine andere asynchrone Funktion sein.

+0

möglich (wahrscheinlich?) Duplizieren - siehe http://stackoverflow.com/questions/1455870/jquery-wait-for-function-to-complete:

Sie könnte so etwas wie (ungetestet) schreiben Weiterverarbeitung –

+0

Jeff, ich denke nicht. Ich benutze JSONP Anruf, der immer synchron ist. – NVI

+1

@NV: JSONP ist nur synchron, wenn als Teil des HTML-Dokuments geparst wird. Wenn es mit dem DOM zur Seite hinzugefügt wird, ist es asynchron. –

Antwort

9

diese Frage Siehe auch: Halt JavaScript execution without locking up the browser

genau tun, was Sie wollen nicht funktioniert. In einer single-threaded ereignisgesteuerten Umgebung können Sie keine Synchronität aus Asynchronität (nur umgekehrt!) Erstellen. Sie sollten die asynchrone Natur der Sprache akzeptieren und Ihren eigenen konsistenten Stil für die Behandlung von Rückrufen entwickeln, damit Ihr Code lesbar/wartbar ist. Sie könnten zum Beispiel wählen, innerhalb einer Callback-Schließung niemals wirkliche Arbeit zu verrichten, sondern rufen einfach eine andere Funktion/Methode der obersten Ebene zur besseren Übersichtlichkeit auf.

1

Die untergeordnete $.ajax() function von jQuery hat mehr Optionen, einschließlich async: [true|false] (Standardwert ist wahr).

Dennoch sollten Sie in den meisten Fällen Bens Rat befolgen und "die asynchrone Natur der Sprache annehmen".

+0

AFAIK, diese Optionen funktionieren nicht mit JSONP-Aufrufen. – NVI

+0

Drew: Danke, dass du das angerufen hast. Es ist wahr, dass JS eine kleine Anzahl von (verwirrend) synchronen Aufrufen hat, wobei "Get" von XMLHttpRequest einer davon ist. –

+0

Ich meinte 'async: false' funktioniert nicht mit JSONP-Aufrufen. – NVI

2

Sie möchten Ihr eigenes $ .getSyncJSON-Objekt erstellen, das $ .ajax ({async: false}) verwendet. Siehe: http://api.jquery.com/jQuery.ajax/.

Ich muss Sie jedoch von dieser Vorgehensweise abraten. Sie können den Browser einfach von allen Eingaben sperren, wodurch Ihre Benutzeroberfläche dem Netzwerk ausgeliefert wird. Aber wenn Sie wissen, was Sie tun, und sich Ihres Anwendungsfalls sicher sind, gehen Sie darauf ein.

2

Stattdessen Hilfsmethoden wie Ihre fetch zu schreiben, die einen Wert zurückgeben, damit sie eine andere Funktion übernehmen, einen „Empfänger“, ihr Ergebnis zu übergeben:

function fetch(receiver) { 

    $.getJSON("blah...", function(data) { 

     receiver(data); 
    }); 
} 

Offensichtlich ist dies überflüssig, weil es genau das ist, wie getJSON funktioniert bereits, aber in einem realistischeren Beispiel würde die fetch-Funktion das Ergebnis irgendwie verarbeiten oder filtern, bevor es weitergeleitet wird.

Dann statt:

document.write(fetch());​ 

Sie tun würde:

fetch(function(result) { document.write(result); }); 

Generatoren verwendet werden können asynchronen Code viel mehr linear in der Art zu machen. Jedes Mal, wenn Sie ein asynchrones Ergebnis benötigen, erhalten Sie eine Funktion, um es zu starten, und der Generator wird fortgesetzt, sobald das Ergebnis verfügbar ist.Es würde ein bisschen Management-Code geben, der den Generator am Laufen hält. Aber das ist nicht viel hilfreich, da Generatoren in allen Browsern nicht Standard sind. Wenn Sie interessiert sind, hier ist ein blog post about using generators to tidy up asynchronous code.

+0

In Ihrem Code-Empfänger sollte innerhalb der Rückruffunktion sein. – NVI

+0

@NV - oops, guten Ruf. –

+0

Ich hatte ein Spiel mit Mozilla Generatoren und sie scheinen ausgezeichnet. Schade, dass sie anderswo nicht weit verbreitet sind. Siehe den Link, den ich am Ende der Antwort hinzugefügt habe. –

2

Es gibt eine Erweiterung der JavaScript-Sprache namens StratifiedJS. Es läuft in jedem Browser, und Sie können genau das tun: asynchrone Probleme auf synchrone/lineare Weise behandeln, ohne Ihren Browser zu blockieren.

Sie können geschichtetes JavaScript aktivieren, z. indem Oni Apollo in Ihrer Webseite wie:

<script src="http://code.onilabs.com/latest/oni-apollo.js"></script> 
<script type="text/sjs"> your StratifiedJS code here </script> 

Und Ihr Code würde wie folgt aussehen:

function fetch() { 
    return require("http").jsonp(
    "http://api.flickr.com/services/feeds/photos_public.gne?" + 
    "tags=cat&tagmode=any&format=json", {cbfield:"jsoncallback"}); 
} 
document.write(fetch());​ 

Oder wenn Sie wirklich jQuery verwenden in StratifiedJS wollen:

require("jquery-binding").install(); 
function fetch() { 
    var url = "http://api.flickr.com/?format=json&...&jsoncallback=?" 
    return $.$getJSON(url); 
} 
document.write(fetch());​ 

docs sind auf http://onilabs.com/docs

2

Die TameJS Bibliothek ist entworfen, um wi zu behandeln th Dieses Problem.

var result = 'snap!'; 
await { 
    $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", defer(result)); 
} 
return result; 
Verwandte Themen