P粉3347213592023-08-24 11:47:12
Your code should look like this:
function foo() { var httpRequest = new XMLHttpRequest(); httpRequest.open('GET', "/echo/json"); httpRequest.send(); return httpRequest.responseText; } var result = foo(); // Always ends up being 'undefined'(
Note, for those using the new fetch API, Angular or Promise, I have added another answer below
)
The
A in AJAX stands for asynchronous. This means that sending the request (or rather receiving the response) is removed from the normal flow of execution. In your example, .send code> returns immediately and the next statement is executed before calling the function you passed as the
success callback
return result; .
This is a simple analogy:
function getFive(){ var a; setTimeout(function(){ a=5; },10); return a; }Since the
a=5 part has not been executed yet, the returned
a value is
undefined. AJAX behaves in such a way that you return the value before the server has a chance to tell your browser what the value is.
reactively write code that tells your program what to do after the calculation is complete.
function onComplete(a){ // When the code completes, do this alert(a); } function getFive(whenDone){ var a; setTimeout(function(){ a=5; whenDone(a); },10); }This is called
CPS. Basically, we pass getFive an action to perform on completion, and we tell our code how to react when the event completes (such as our AJAX call, or in this case a timeout) .
< /p>Usage is:
getFive(onComplete);"5" will be prompted on the screen.
(violin).
Possible solutions
Don't do it! Felix's answer presents some compelling arguments as to why this is a bad idea. All in all, it freezes the user's browser until the server returns a response and creates a very bad user experience. Here's another short summary from MDN explaining why:
If youhave to do this, you can pass a flag. The specific methods are as follows:
var request = new XMLHttpRequest(); request.open('GET', 'yourURL', false); // `false` makes the request synchronous request.send(null); if (request.status === 200) {// That's HTTP for 'ok' console.log(request.responseText); }2. Reorganization code
foo accept a callback. We'll tell the code how to
react when
foo completes.
var result = foo(); // Code that depends on `result` goes herebecome:
foo(function(result) { // Code that depends on `result` });
Here we're passing an anonymous function, but we could just as easily pass a reference to an existing function, making it look like:
function myHandler(result) { // Code that depends on `result` } foo(myHandler);
For more details on how to accomplish this type of callback design, check out Felix's answer.
Now, let's define foo itself to perform the corresponding operations
function foo(callback) { var httpRequest = new XMLHttpRequest(); httpRequest.onload = function(){ // When the request is loaded callback(httpRequest.responseText);// We're calling our method }; httpRequest.open('GET', "/echo/json"); httpRequest.send(); }
Now we have the foo function accept an action to run when AJAX completes successfully. We can extend this functionality further by checking if the response status is not 200 and taking appropriate action (creating a failure handler, etc.). It effectively solved our problem.
If you're still having trouble understanding this, Read the AJAX Get Started Guide on MDN.
P粉6429205222023-08-24 00:16:16
A in Ajax stands for asynchronous. This means that sending the request (or rather receiving the response) is removed from the normal flow of execution. In your example, $.ajax
returns immediately, and the next statement return result;
is executed before the function you pass as the success
callback is even called .
Here's an analogy that hopefully makes the difference between synchronous and asynchronous streams clearer:
Imagine you call a friend and ask him to find some information for you. Although it might take a while, you wait by the phone, staring into space, until your friend gives you the answer you need.
The same thing happens when you make a function call that contains "normal" code:
function findItem() { var item; while(item_not_found) { // search } return item; } var item = findItem(); // Do something with item doSomethingElse();
Although findItem
may take a long time to execute, any code after var item = findItem();
must wait until the function returns result.
You call your friend again for the same reason. But this time you tell him that you are anxious and he should call you back on your mobile . You hang up the phone, leave the house, and do whatever you planned to do. Once your friend calls you back, you are processing the information he gave you.
This is exactly what happens when you make an Ajax request.
findItem(function(item) { // Do something with the item }); doSomethingElse();
Does not wait for a response, but continues execution immediately and executes the statement after the Ajax call. In order to finally get the response, you need to provide a function that is called after the response is received, a callback (notice anything? Callback?). Any statements after this call will be executed before the callback is called.
Embrace the asynchronous nature of JavaScript! While some asynchronous operations provide synchronous counterparts (as does "Ajax"), their use is generally discouraged, especially in a browser context.
Why is it bad, you ask?
JavaScript runs in the browser's UI thread, and any long-running process can lock the UI, making it unresponsive. In addition, there is an upper limit on the execution time of JavaScript, and the browser will ask the user whether to continue execution.
All of these can lead to a very bad user experience. The user will not be able to tell if everything is working properly. In addition, the effect will be worse for users with slower Internet speeds.
Below we will introduce three different solutions, which all build on each other:
async/await
(ES2017, works in older browsers if you use a transpiler or regenerator)then()
(ES2015, works in older browsers if you use one of the many Promise libraries) All three features are available in current browsers and Node 7.
async/await for promises
The 2017 release of ECMAScript introduced syntax-level support for asynchronous functions. With async
and await
you can write asynchronously in a "synchronous style". The code is still asynchronous, but easier to read/understand.
async/await
Built on Promise: async
Functions always return a Promise. await
"Unwraps" a Promise and either produces the value of the Promise as resolved, or throws an error if the Promise is rejected.
IMPORTANT: You can only use await
within an JavaScript Modules. Top-level await
is not supported outside of modules, so you may have to create an async IIFE (Immediately Invoked Function Expression) to start an async
context (if not using the module).
You can read about async<的更多信息/code>
and await< MDN 上的 /code>
.
Here is an example detailing the delay function findItem()
above:
// Using 'superagent' which will return a promise. var superagent = require('superagent') // This is isn't declared as `async` because it already returns a promise function delay() { // `delay` returns a promise return new Promise(function(resolve, reject) { // Only `delay` is able to resolve or reject the promise setTimeout(function() { resolve(42); // After 3 seconds, resolve the promise with value 42 }, 3000); }); } async function getAllBooks() { try { // GET a list of book IDs of the current user var bookIDs = await superagent.get('/user/books'); // wait for 3 seconds (just for the sake of this example) await delay(); // GET information about each book return superagent.get('/books/ids='+JSON.stringify(bookIDs)); } catch(error) { // If any of the awaited promises was rejected, this catch block // would catch the rejection reason return null; } } // Start an IIFE to use `await` at the top level (async function(){ let books = await getAllBooks(); console.log(books); })();
The current browser and node versions support async/await
. You can also convert your code to ES5 with the help of regenerator (or a tool that uses regenerator) to support older environments such as Babel).
Callback refers to when function 1 is passed to function 2. Function 2 can call function 1 when it is ready. In the context of an asynchronous process, the callback is called whenever the asynchronous process completes. Normally, the results are passed to the callback.
In the question's example, you could make foo
accept a callback and use it as the success
callback. So this
var result = foo(); // Code that depends on 'result'
became
foo(function(result) { // Code that depends on 'result' });
Here we define an "inline" function, but you can pass any function reference:
function myCallback(result) { // Code that depends on 'result' } foo(myCallback);
foo
itself is defined as follows:
function foo(callback) { $.ajax({ // ... success: callback }); }
callback
will reference the function we passed to foo
when we called it, and pass it to success
. ie. Once the Ajax request is successful, $.ajax
will call callback
and pass the response to the callback (which can be referenced with result
since that's how we define callbacks) .
You can also process the response before passing it to the callback:
function foo(callback) { $.ajax({ // ... success: function(response) { // For example, filter the response callback(filtered_response); } }); }
Writing code using callbacks is easier than it looks. After all, JavaScript in browsers is largely event-driven (DOM events). Receiving an Ajax response is nothing more than an event. Difficulties may arise when you have to use third-party code, but most problems can be solved by simply thinking about the application flow.
The Promise API is a new ECMAScript 6 (ES2015) feature, but it already has good browser support. There are also many libraries that implement the standard Promises API and provide additional methods to simplify the use and composition of asynchronous functions (e.g. Bluebird).
Promise is a container for future values. When a Promise receives a value (resolved) or is canceled (rejected), it notifies all "listeners" that want to access the value. < /p>
The advantage over normal callbacks is that they allow you to decouple your code and are easier to write.
This is an example of using Promise:
function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}
delay()
.then(function(v) { // `delay` returns a promise
console.log(v); // Log the value once it is resolved
})
.catch(function(v) {
// Or do something else if it is rejected
// (it would not happen in this example, since `reject` is not called).
});
.as-console-wrapper { max-height: 100% !important; top: 0; }