2017-03-14 4 views
0

Ich mache einen synchronen REST-API-Aufruf im Hauptthread. jQuery (oder Browser?) beschwert sich. Aber ich weiß nicht, wie man es asynchron programmiert, oder zumindest ist der Code weniger verwirrend zu lesen, wie er ist.jQuery synchroner REST-API-Aufruf schlägt fehl, Objekt zurückzugeben

Dies ist eine vereinfachte Version von dem, was ich tue:

<html> 
    <head> 
     <script type="text/javascript" src="/js/jquery.min.js" ></script> 
    </head> 
    <body> 
     <script type="text/javascript"> 
      function get_foobar(val1, val2){ 
       $.ajax({ 
        url: 'http://localhost:8000/api/' + va1 + '/' + val2, 
        success: function (data) { 
         let my_object = $.parseJSON(data) 
         //console.log(data); 
         console.log(my_object); 
         let params = my_object['params']; 
         let blob = my_object['the_thing']; 
         var foobar = new FooBar(var1, var2, params, blob); 

         return foobar; // <- object created here ... 
        }, 
        async: false      
       }); 

      } 

      $(document.ready(function(){ 
       foobar = get_foobar($('#field1').val, $('#field2').val()); 
       console.log(foobar); // <- undefined here ... wtf? 
      }); 
     </script> 
    </body> 
</html> 

Warum ist die Funktion nicht das foobar Objekt zurückkehrt, die erstellt wird?

+0

entfernen 'async: false' und der Browser über sync ajax auf dem Haupt-Thread beschwert wird gestoppt. – Trevor

+0

'Ich mache eine asynchrone ...' dann machst du 'async: false' - ist es einfach du willst wissen, wie es geht? Diese widersprechen sich –

+1

@DarrenSweeney: gut entdeckt.Eigentlich wollte ich SYNCHRON anrufen. Ich habe das gerade bemerkt und wollte gerade meinen Titel ändern, als du mich dazu geschlagen hast. –

Antwort

0

Es gibt ein paar Probleme hier.

  1. Sie geben nichts in get_foobar zurück.
  2. Sie können nicht auf den Rückgabewert des Erfolgsrückrufs zugreifen.
  3. Sie sollten nie async: false

Ein üblicher Weg, dies zu lösen, verwenden Promises

function get_foobar(val1, val2) { 
    return new Promise(function(resolve, reject) { 
     $.ajax({ 
      url: 'http://localhost:8000/api/' + va1 + '/' + val2, 
      success: function (data) { 
       let my_object = $.parseJSON(data) 
       //console.log(data); 
       console.log(my_object); 
       let params = my_object['params']; 
       let blob = my_object['the_thing']; 
       var foobar = new FooBar(var1, var2, params, blob); 

       resolve(foobar); // <- resolve the object created here ... 
      }, 
      error: function(err) { 
       reject(err); // REJECT any errors that occur in request 
      }    
     }); 
    }); 
} 

get_foobar($('#field1').val, $('#field2').val()) 
    .then(function(foobar) { 
     console.log(foobar) 
    }) 
    .catch(function(error) { 
     console.error('something went wrong!', error); 
    }); 
+0

Aber ich möchte ein ** synchronus machen ** Aufruf an die REST-API. Die nächste Zeile hängt davon ab, dass das Objekt vom vorhergehenden Funktionsaufruf zurückgegeben wurde. Ich nehme an, ich könnte einen Callback verwenden - aber es macht den Code unnötig kompliziert ...:/ –

+0

Die Idee ist, Ihren Code, der von den zurückgegebenen Daten abhängt, in Ihren 'then' Callback zu verschieben. Ich denke nicht, dass es unnötig kompliziert ist, auf Promises umzusteigen, aber ich denke, das ist eine Frage der Meinung. Synchrone AJAX-Aufrufe sind seit jQuery 1.8 veraltet. –

+0

Hmm, ich muss eine Menge Code umgestalten - wenn ich Versprechungen verwenden soll ... Ich denke, es ist etwas drakonisch für JQuery, einen bestimmten Stil aufzuzwingen Programmierung auf Codern ... :( –

0

Lösung auf Rückruf:

<html> 
    <head> 
     <script type="text/javascript" src="/js/jquery.min.js" ></script> 
    </head> 
    <body> 
     <script type="text/javascript"> 
      function get_foobar(val1, val2, cb){ 
       $.ajax({ 
        url: 'http://localhost:8000/api/' + va1 + '/' + val2, 
        success: function (data) { 
         let my_object = $.parseJSON(data) 
         //console.log(data); 
         console.log(my_object); 
         let params = my_object['params']; 
         let blob = my_object['the_thing']; 
         var foobar = new FooBar(var1, var2, params, blob); 
         cb(foobar); 
        }, 
        //async: false//no reason to use it 
       }); 

      } 

      $(document.ready(function(){ 
       get_foobar($('#field1').val, $('#field2').val(), function(foobar){ 
        console.log(foobar); 
       }); 
      }); 
     </script> 
    </body> 
</html> 
0

Hier ist ein Beispiel, das das Problem Sie konfrontiert sind, und der richtige Weg, Daten asynchron zu bekommen zeigt zu verwenden ist (Leider ist es eine schlechte Übung, die Ajax-Anfrage synchron zu machen, und die Unterstützung dafür wird in Zukunft aus den Browsern entfernt, also sollten Sie sich auf keinen Fall darauf verlassen).

Das Hauptproblem ist, dass zu dem Zeitpunkt, zu dem Ihr asynchroner Code ausgeführt wird, die Funktion, die sie aufgerufen hat, längst ausgeführt und bereits zurückgegeben wurde. In diesem Beispiel möchten Sie eine Funktion wie timer1, um ein Ergebnis zurückzugeben, aber es gibt sein Ergebnis an den inneren Code setTimeout zurück, wo es tatsächlich aufgerufen wird. setTimeout gibt nichts zurück (daher undefined). Was Sie tun müssen, ist promises oder für einfache Fälle, Rückrufe zu verwenden. Das zweite Beispiel in dem folgenden Code verwendet Rückrufe, um zusätzlichen Code nach dem asynchronen Vorgang auszuführen.

Ich empfehle Ihnen, dies zu lesen: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop. Es wird Ihnen helfen, asynchronen Code in JavaScript zu verstehen, und warum die Dinge so funktionieren, wie sie funktionieren.

var log = (function(){ 
 
    var out = document.querySelector('#out'); 
 
    return function(msg){ 
 
    out.innerHTML += '<div>' + msg + '</div>'; 
 
    } 
 
})(); 
 

 

 
function getSomethingAsyncTheWrongWay(){ 
 
    setTimeout(function timer1(){ 
 
    log('Round 1: First in code, last in console'); 
 
    return 'Result'; 
 
    }, 1000); 
 
} 
 

 

 
log(getSomethingAsyncTheWrongWay()); 
 

 
log('Round 1: Last in code, first in console'); 
 

 

 
function getSomethingAsyncTheRightWay(callback){ 
 
    setTimeout(function timer2(){ 
 
    log('Round 2: First in code, last in console'); 
 
    callback('Result'); 
 
    }, 1000); 
 
} 
 

 
getSomethingAsyncTheRightWay(function(result){ 
 
    log(result); 
 
}); 
 

 
log('Round 2: Last in code, first in console');
#out{ 
 
    color:green; 
 
    background:#000; 
 
    font-family:courier new; 
 
    padding:1em; 
 
    font-weight:bold; 
 
}
<div id=out></div>

Verwandte Themen