2014-08-27 9 views
7

Ich mag würde die Google Maps Geocoding API mit einem Versprechen wie diese nennen:einen Wert von einem Versprechen Rückkehr

function makeGeoCodingRequest(address,bounds) 
{ 
    /* 
     Input parameters: 
      address:a string 
      bounds: an object of class google.maps.LatLngBounds(southWest,northEast) 

     This will return a set of locations from the google geocoding library for the given query 
    */ 
    var url="https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=AIzaSyD9GBloPC20X-1kWRo7sm_0z5xvCiaSd3c"; 
    var promise,response; 
    var messages={ 
      "ZERO_RESULTS":"No results were found", 
      "OVER_QUERY_LIMIT":"We are over the query limit.Wait awhile before making a request", 
      "REQUEST_DENIED":"Request was denied,probably using a bad or expired API Key", 
      "INVALID_REQUEST":"Request was sent without the required address,component or component", 
      "UNKNOWN_ERROR": "There was an error somewhere on Google's servers" 
    }; 
    if(address) 
     promise=Q($.ajax({ 
      type: "GET", 
      url: "https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=API_KEY" 
     })); 
     return promise.then(function(data) { 
      if (data.status === "OK") return data; 
      else console.error(messages[data.status]); 
      return null;  
     }); 
} 

Wenn ich die Funktion makeGeoCodingRequest Anfrage nennen, finde ich, dass ich ein Versprechen statt eines erhalten Wert:

var geo=makeGeoCodingRequest(address); 
console.log(Q.isPromise(geo));//returns true 

Warum nicht versprechen.dann ausgeführt, bevor der Wert zurückgegeben wurde? Wie kann ich einen Wert aus diesem Versprechen anstelle eines anderen versprechen?

Antwort

5

Wenn Sie auf ein Versprechen angewiesen sind, um Ihre Daten zurückzugeben, müssen Sie ein Versprechen von Ihrer Funktion zurückgeben.

Sobald eine Funktion in Ihrem Callstack asynchron ist, müssen alle Funktionen, die sie aufrufen möchten, async sein, wenn Sie die lineare Ausführung fortsetzen möchten. (async = gibt ein Versprechen zurück)

Beachten Sie, dass Ihre if-Anweisung keine geschweiften Klammern hat und daher nur die erste Anweisung nach der Ausführung ausgeführt wird, wenn die Bedingung fehlschlägt.

Ich habe es in diesem Beispiel behoben. Beachten Sie die Anmerkungen, die ich hinzugefügt habe.

if(address){ 
    promise=Q($.ajax({ 
     type: "GET", 
     url: "https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=API_KEY" 
    })); 
    return promise.then(function(data) { 
     // whatever you return here will also become the resolve value of the promise returned by makeGeoCodingRequest 
     // If you don't want to validate the data, you can in fact just return the promise variable directly 
     // you probably want to return a rejected promise here if status is not what you expected 
     if (data.status === "OK") return data; 
      else console.error(messages[data.status]); 
     return null;  
    }); 
} 

Sie müssen auf folgende Weise aufrufen.

makeGeoCodingRequest(address,bounds).then(function(data){ 
    // this will contain whatever 
    console.log(data); 
}); 
+0

Wenn ich stattdessen entscheide, 'promise.then (...)' und 'return promise' zu ​​verwenden und dann' makeGeoCodingRequest (adresse, bounds) .then (...) ', wäre es dann immer noch dasselbe? – vamsiampolu

+0

Ja, das Versprechen, das von 'makeGeoCodingRequest' zurückgegeben wird, hat denselben Wert des Rückgabewerts in Ihrem 'promise.then'-Handler. Sie können ablehnen, indem Sie etwas wie 'Q.reject (neuer Fehler (" HTTP-Anforderung fehlgeschlagen "+ data.status)) zurückschicken.' –

+1

Danke für die Antwort, alles funktioniert, einschließlich Q.reject. – vamsiampolu

-1

Wenn Ihr Code warten soll, bis die asynchrone Aktion abgeschlossen ist, bevor Sie fortfahren (BAD IDEA - die Seite friert ein, während die Anfrage abgeschlossen wird), fügen Sie async: false den Parametern der AJAX-Anfrage hinzu.

Meine Empfehlung ist jedoch, makeGeoCodingRequest nichts direkt zurückgeben - und geben Sie einfach ein zusätzliches Argument, requestCallback, so dass sein Aufrufer in einer Funktion übergeben kann, die aufgerufen wird, wenn die Daten verfügbar sind. Rufen Sie diese Funktion mit den resultierenden Daten innerhalb Ihrer promise.then-Funktion auf.

+0

Wenn es ein Problem mit meiner Antwort gibt, könnte vielleicht jemand einen Vorschlag zur Verbesserung geben? – Katana314

+0

Ihre Empfehlung, Synchronisierungsanfragen zu stellen, spricht nicht die Tatsache an, dass OP das Versprechungskonzept nicht versteht. Abgesehen davon ist es falsch. Sie müssen ein 'async: false 'setzen, um eine Synchronisierungsanfrage zu erhalten. So wie du dich selbst in fast allen Umständen bemerkt hast, ist das eine schlechte Idee. Die Einführung eines Callbacks in der Funktion ist ebenfalls eine schlechte Idee, da 'makeGeoCodingRequest' einfach ein Versprechen abgeben sollte, da beides ein Anti-Pattern ist und für einen Anfänger verwirrend ist. –

+0

Ah, richtig; Ich habe den Async-Wert falsch angegeben. Dieser Teil sollte eigentlich eine Erklärung liefern, warum sein Code einen Wert nicht einfach so einfach zurückgeben kann. Ich schätze, ich war nicht persönlich mit Ideologien vertraut, deren Funktionen das gegebene "Versprechen" -Objekt weiter verwenden sollten und die auf eine vereinfachte Funktion übertragen werden sollten; Das ist eigentlich neu für mich. Ich habe nicht vorgeschlagen, dass er beides benutzt. – Katana314

0

Sie geben ein Versprechen von der Funktion makeGeoCodingRequest zurück. Das ist eine gute Sache für mich, dies hilft Ihnen, weitere Async-Aufrufe zu ketten, wenn dies in Zukunft erforderlich ist. Was ich vorschlagen würde, ist, eine .then() für die zurückgegebene Versprechen zu verwenden und zu prüfen, ob das Versprechen einen zurückgegebenen Wert oder Fehler in der folgenden Weise hat.

3

finde ich, dass ich ein Versprechen anstelle eines Wertes

Ja, erhalten, da die Operation asynchron ist und gibt ein Versprechen, das den zukünftigen Wert darstellt.

Warum wird nicht versprochen, bevor der Wert zurückgegeben wurde?

Weil es asynchron ist. .then wird (must) seinen Callback nie ausführen, bevor es ein anderes Versprechen zurückgibt.

Wie kann ich einen Wert aus diesem Versprechen anstelle eines anderen Versprechens erhalten?

Sie erhalten den Wert in dem Rückruf:

makeGeoCodingRequest(address).then(function(geo) { 
    console.log(geo) 
    console.log(Q.isPromise(geo)); // false 
    // do anything with the value here 
}) 
// if you need to do anything with the result of the callback computation: 
// you're getting back another promise for that! 

es unmöglich ist, sie aus dem Versprechen (many have tried) synchron zu erhalten. Das würde bedeuten, die Ausführung zu blockieren, was wir nicht wollen - bleiben wir asynchron und nicht blockierend!

+0

Sehr gut erklärt. Es könnte interessant sein, Hinweise darauf zu geben, wie man die Antwort von einem AJAX-Aufruf zurückgibt und andere Fragen, die das Problem betreffen. –

+0

Was Sie im Wesentlichen sagen, ist, dass jede Sache, die Sie tun wollen, innerhalb der 'then' Methode getan werden muss, die' Daten' verwendet, die ich als 'Argument' im' Callback' dazu erhalte.Nur wie 'Rückrufe', ich vermuten. – vamsiampolu

+1

Ja, [wie Rückrufe] (http://stackoverflow.com/a/22562045/1048572). Nur dass Sie für das Ergebnis des Callbacks ein weiteres Versprechen erhalten, das sie verkettbar macht. – Bergi

Verwandte Themen