gpt4 book ai didi

How do I return the response from an asynchronous call?(如何从异步调用返回响应?)

转载 作者:bug小助手 更新时间:2023-10-24 19:21:57 28 4
gpt4 key购买 nike



How do I return the response/result from a function foo that makes an asynchronous request?

如何从发出异步请求的函数foo返回响应/结果?


I am trying to return the value from the callback, as well as assigning the result to a local variable inside the function and returning that one, but none of those ways actually return the response — they all return undefined or whatever the initial value of the variable result is.

我试图从回调中返回值,并将结果赋给函数内部的局部变量并返回该变量,但这些方法都没有真正返回响应-它们都返回未定义的或无论变量结果的初始值是什么。


Example of an asynchronous function that accepts a callback (using jQuery's ajax function):

接受回调的异步函数示例(使用jQuery的AJAX函数):


function foo() {
var result;

$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});

return result; // It always returns `undefined`
}

Example using Node.js:

使用Node.js的示例:


function foo() {
var result;

fs.readFile("path/to/file", function(err, data) {
result = data;
// return data; // <- I tried that one as well
});

return result; // It always returns `undefined`
}

Example using the then block of a promise:

使用承诺的THEN块的示例:


function foo() {
var result;

fetch(url).then(function(response) {
result = response;
// return response; // <- I tried that one as well
});

return result; // It always returns `undefined`
}

更多回答

use deasync like this stackoverflow.com/a/47051880/2083877

像这样使用deasync堆栈溢出.com/a/47051880/2083877

@SunilKumar I don't think this is useful. OP made this question and self-answer to document how to get the response from async calls. Suggesting a 3rd party module defeats such purpose, and IMO the paradigm introduced by that module is not good practice.

@SunilKumar我不认为这是有用的。OP提出了这个问题并自我回答,以记录如何从异步调用中获得响应。建议第三方模块会破坏这种目的,而由该模块引入的范例并不是好的做法。

@Liam: It's just an example for an asynchronous function that accepts a callback.

@Liam:这只是一个接受回调的异步函数的示例。

Promises provide a cleaner and more structured way to deal with asynchronous operations. You can create promise that represents the result of the asynchronous call. The promise can be resolved with the response or rejected with an error.

承诺提供了一种更干净、更结构化的方式来处理异步操作。您可以创建表示异步调用结果的Promise。承诺可以通过响应解决,也可以通过错误拒绝。

优秀答案推荐


→ For a more general explanation of asynchronous behaviour with different examples, see Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference


→ If you already understand the problem, skip to the possible solutions below.



The problem


The A in Ajax stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example, $.ajax returns immediately and the next statement, return result;, is executed before the function you passed as success callback was even called.

AJAX中的A代表异步。这意味着发送请求(或者更确切地说,接收响应)不在正常执行流程中。在您的示例中,$.ajax立即返回,并且在您作为成功回调传递的函数被调用之前就执行下一条语句Return Result;。


Here is an analogy which hopefully makes the difference between synchronous and asynchronous flow clearer:

下面是一个类比,它有望更清楚地区分同步流和异步流:


Synchronous


Imagine you make a phone call to a friend and ask him to look something up for you. Although it might take a while, you wait on the phone and stare into space, until your friend gives you the answer that you needed.

想象一下,你给一位朋友打了个电话,让他帮你查个东西。尽管这可能需要一段时间,但你会在电话上等待,凝视着天空,直到你的朋友给你你需要的答案。


The same is happening when you make a function call containing "normal" code:

当您进行包含“正常”代码的函数调用时,也会发生同样的情况:


function findItem() {
var item;
while(item_not_found) {
// search
}
return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

Even though findItem might take a long time to execute, any code coming after var item = findItem(); has to wait until the function returns the result.

尽管findItem可能需要很长时间才能执行,但var Item=findItem();之后的任何代码都必须等待,直到函数返回结果。


Asynchronous


You call your friend again for the same reason. But this time you tell him that you are in a hurry and he should call you back on your mobile phone. You hang up, leave the house, and do whatever you planned to do. Once your friend calls you back, you are dealing with the information he gave to you.

你为了同样的原因又给你的朋友打了电话。但这一次你告诉他你很匆忙,他应该用你的手机给你回电话。你挂断电话,离开家,然后做你打算做的任何事情。一旦你的朋友给你回电话,你就是在处理他给你的信息。


That's exactly what's happening when you do an Ajax request.

这正是您在执行AJAX请求时所发生的事情。


findItem(function(item) {
// Do something with the item
});
doSomethingElse();

Instead of waiting for the response, the execution continues immediately and the statement after the Ajax call is executed. To get the response eventually, you provide a function to be called once the response was received, a callback (notice something? call back ?). Any statement coming after that call is executed before the callback is called.

不是等待响应,而是立即继续执行,并执行AJAX调用之后的语句。为了最终获得响应,您提供了一个在接收到响应后要调用的函数,即一个回调(注意到什么了吗?回电?)。在该调用之后的任何语句都在回调被调用之前执行。




Solution(s)


Embrace the asynchronous nature of JavaScript! While certain asynchronous operations provide synchronous counterparts (so does "Ajax"), it's generally discouraged to use them, especially in a browser context.

拥抱JavaScript的异步性!虽然某些异步操作提供同步对应物(“AJAX”也是如此),但通常不鼓励使用它们,尤其是在浏览器上下文中。


Why is it bad do you ask?

你会问为什么它不好?


JavaScript runs in the UI thread of the browser and any long-running process will lock the UI, making it unresponsive. Additionally, there is an upper limit on the execution time for JavaScript and the browser will ask the user whether to continue the execution or not.

JavaScript在浏览器的UI线程中运行,任何长时间运行的进程都将锁定UI,使其无响应。此外,对JavaScript的执行时间有上限,浏览器会询问用户是否继续执行。


All of this results in a really bad user experience. The user won't be able to tell whether everything is working fine or not. Furthermore, the effect will be worse for users with a slow connection.

所有这些都会导致非常糟糕的用户体验。用户将无法判断一切是否运行正常。此外,对于连接速度较慢的用户,效果会更差。


In the following we will look at three different solutions that are all building on top of each other:

在以下内容中,我们将介绍三种不同的解决方案,它们都建立在彼此之上:



  • Promises with async/await (ES2017+, available in older browsers if you use a transpiler or regenerator)

  • Callbacks (popular in node)

  • Promises with then() (ES2015+, available in older browsers if you use one of the many promise libraries)


All three are available in current browsers, and node 7+.

这三个版本都可以在当前的浏览器和Node7+中使用。




ES2017+: Promises with async/await


The ECMAScript version released in 2017 introduced syntax-level support for asynchronous functions. With the help of async and await, you can write asynchronous in a "synchronous style". The code is still asynchronous, but it's easier to read/understand.

2017年发布的ECMAScript版本引入了对异步函数的语法级支持。在Async和Await的帮助下,您可以以“同步风格”编写异步代码。代码仍然是异步的,但更易于阅读/理解。


async/await builds on top of promises: an async function always returns a promise. await "unwraps" a promise and either result in the value the promise was resolved with or throws an error if the promise was rejected.

异步/等待建立在承诺之上:异步函数总是返回承诺。等待“展开”一个承诺,如果承诺被拒绝,要么产生承诺解析时的值,要么抛出一个错误。


Important: You can only use await inside an async function or in a JavaScript module. Top-level await is not supported outside of modules, so you might have to make an async IIFE (Immediately Invoked Function Expression) to start an async context if not using a module.

重要提示:您只能在异步函数内或在JavaScript模块中使用aWait。在模块之外不支持顶级等待,因此如果不使用模块,您可能必须创建一个异步生命周期(立即调用的函数表达式)来启动一个异步上下文。


You can read more about async and await on MDN.

你可以阅读更多关于异步的内容,并在MDN上等待。


Here is an example that elaborates the delay function findItem() above:

下面的示例详细说明了上面的延迟函数findItem():


// 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);
})();

Current browser and node versions support async/await. You can also support older environments by transforming your code to ES5 with the help of regenerator (or tools that use regenerator, such as Babel).

当前浏览器和节点版本支持异步/等待。您还可以通过在再生器(或使用再生器的工具,如Babel)的帮助下将代码转换为ES5来支持较旧的环境。




Let functions accept callbacks


A callback is when function 1 is passed to function 2. Function 2 can call function 1 whenever it is ready. In the context of an asynchronous process, the callback will be called whenever the asynchronous process is done. Usually, the result is passed to the callback.

回调是当函数%1传递给函数%2时。函数%2可以在准备好时调用函数%1。在异步流程的上下文中,只要完成了异步流程,就会调用回调。通常,结果被传递给回调。


In the example of the question, you can make foo accept a callback and use it as success callback. So this

在问题的示例中,您可以让foo接受回调并将其用作成功回调。所以这就是


var result = foo();
// Code that depends on 'result'

becomes

vbl.成为


foo(function(result) {
// Code that depends on 'result'
});

Here we defined the function "inline" but you can pass any function reference:

这里我们定义了函数“inline”,但您可以传递任何函数引用:


function myCallback(result) {
// Code that depends on 'result'
}

foo(myCallback);

foo itself is defined as follows:

Foo本身的定义如下:


function foo(callback) {
$.ajax({
// ...
success: callback
});
}

callback will refer to the function we pass to foo when we call it and we pass it on to success. I.e. once the Ajax request is successful, $.ajax will call callback and pass the response to the callback (which can be referred to with result, since this is how we defined the callback).

回调将引用我们在调用foo并将其传递给Success时传递给foo的函数。即,一旦AJAX请求成功,$.ajax将调用回调并将响应传递给回调(可以用Result引用,因为这是我们定义回调的方式)。


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);
}
});
}

It's easier to write code using callbacks than it may seem. After all, JavaScript in the browser is heavily event-driven (DOM events). Receiving the Ajax response is nothing else but an event.
Difficulties could arise when you have to work with third-party code, but most problems can be solved by just thinking through the application flow.

使用回调编写代码比看起来容易。毕竟,浏览器中的JavaScript在很大程度上是事件驱动的(DOM事件)。接收Ajax响应只是一个事件。当您必须使用第三方代码时,可能会出现困难,但大多数问题都可以通过思考应用程序流来解决。




ES2015+: Promises with then()


The Promise API is a new feature of ECMAScript 6 (ES2015), but it has good browser support already. There are also many libraries which implement the standard Promises API and provide additional methods to ease the use and composition of asynchronous functions (e.g., bluebird).

Promise API是ECMAScript6(ES2015)的一个新特性,但它已经有了很好的浏览器支持。还有许多库实现了标准的Promises API,并提供了额外的方法来简化异步函数的使用和组合(例如,BlueBird)。


Promises are containers for future values. When the promise receives the value (it is resolved) or when it is canceled (rejected), it notifies all of its "listeners" who want to access this value.

承诺是未来价值的容器。当承诺接收到该值(它被解析)或当它被取消(拒绝)时,它通知所有想要访问该值的“监听器”。


The advantage over plain callbacks is that they allow you to decouple your code and they are easier to compose.

与普通回调相比的优势在于,它们允许您将代码解耦,并且更易于编写。


Here is an example of using 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);
});
}

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; }




Applied to our Ajax call we could use promises like this:

应用到我们的AJAX调用中,我们可以使用这样的承诺:




function ajax(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(this.responseText);
};
xhr.onerror = reject;
xhr.open('GET', url);
xhr.send();
});
}

ajax("https://jsonplaceholder.typicode.com/todos/1")
.then(function(result) {
console.log(result); // Code depending on result
})
.catch(function() {
// An error occurred
});

.as-console-wrapper { max-height: 100% !important; top: 0; }




Describing all the advantages that promise offer is beyond the scope of this answer, but if you write new code, you should seriously consider them. They provide a great abstraction and separation of your code.

描述Promise提供的所有优势超出了本答案的范围,但如果您编写新代码,您应该认真考虑它们。它们为您的代码提供了很好的抽象和分离。


More information about promises: HTML5 rocks - JavaScript Promises.

更多关于承诺的信息:HTML5令人震惊--JavaScript承诺。


Side note: jQuery's deferred objects


Deferred objects are jQuery's custom implementation of promises (before the Promise API was standardized). They behave almost like promises but expose a slightly different API.

延迟对象是jQuery对Promise的定制实现(在Promise API标准化之前)。它们的行为几乎像承诺,但公开了一个略有不同的API。


Every Ajax method of jQuery already returns a "deferred object" (actually a promise of a deferred object) which you can just return from your function:

JQuery的每个AJAX方法都已经返回了一个“延迟对象”(实际上是一个延迟对象的承诺),您只需从您的函数返回:


function ajax() {
return $.ajax(...);
}

ajax().done(function(result) {
// Code depending on result
}).fail(function() {
// An error occurred
});

Side note: Promise gotchas


Keep in mind that promises and deferred objects are just containers for a future value, they are not the value itself. For example, suppose you had the following:

请记住,承诺和延迟对象只是未来价值的容器,而不是价值本身。例如,假设您具有以下内容:


function checkPassword() {
return $.ajax({
url: '/password',
data: {
username: $('#username').val(),
password: $('#password').val()
},
type: 'POST',
dataType: 'json'
});
}

if (checkPassword()) {
// Tell the user they're logged in
}

This code misunderstands the above asynchronous issues. Specifically, $.ajax() doesn't freeze the code while it checks the '/password' page on your server - it sends a request to the server and while it waits, it immediately returns a jQuery Ajax Deferred object, not the response from the server. That means the if statement is going to always get this Deferred object, treat it as true, and proceed as though the user is logged in. Not good.

这段代码误解了上面的异步问题。具体地说,$.ajax()在检查服务器上的‘/password’页面时不会冻结代码--它向服务器发送一个请求,并在等待期间立即返回一个jQuery AJAX延迟对象,而不是来自服务器的响应。这意味着if语句将始终获取这个延迟对象,将其视为真,并像用户已登录一样继续操作。不太好。


But the fix is easy:

但解决办法很简单:


checkPassword()
.done(function(r) {
if (r) {
// Tell the user they're logged in
} else {
// Tell the user their password was bad
}
})
.fail(function(x) {
// Tell the user something bad happened
});



Not recommended: Synchronous "Ajax" calls


As I mentioned, some(!) asynchronous operations have synchronous counterparts. I don't advocate their use, but for completeness' sake, here is how you would perform a synchronous call:

正如我提到的,有些(!)异步操作具有同步的对应物。我不提倡使用它们,但为了完整起见,下面是执行同步调用的方法:


Without jQuery


If you directly use a XMLHttpRequest object, pass false as third argument to .open.

如果直接使用XMLHttpRequest对象,则将False作为第三个参数传递给.Open。


jQuery


If you use jQuery, you can set the async option to false. Note that this option is deprecated since jQuery 1.8.
You can then either still use a success callback or access the responseText property of the jqXHR object:

如果使用jQuery,则可以将Async选项设置为FALSE。请注意,从jQuery 1.8开始,不再推荐使用该选项。然后,您仍然可以使用成功回调或访问jqXHR对象的ResponseText属性:


function foo() {
var jqXHR = $.ajax({
//...
async: false
});
return jqXHR.responseText;
}

If you use any other jQuery Ajax method, such as $.get, $.getJSON, etc., you have to change it to $.ajax (since you can only pass configuration parameters to $.ajax).

如果您使用任何其他jQuery AJAX方法,如$.get、$.getJSON等,则必须将其更改为$.ajax(因为您只能将配置参数传递给$.ajax)。


Heads up! It is not possible to make a synchronous JSONP request. JSONP by its very nature is always asynchronous (one more reason to not even consider this option).

当心!不可能发出同步的JSONP请求。JSONP本质上总是异步的(甚至不考虑这个选项的另一个原因)。



If you're not using jQuery in your code, this answer is for you


Your code should be something along the lines of 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'

Felix Kling did a fine job writing an answer for people using jQuery for AJAX, but I've decided to provide an alternative for people who aren't.

Felix Kling为使用jQuery for AJAX的用户编写了一个很好的答案,但我决定为不使用jQuery的用户提供一个替代方案。


(Note, for those using the new fetch API, Angular or promises I've added another answer below)

(请注意,对于那些使用新的FETCH API、ANGLE或Promise的用户,我在下面添加了另一个答案)




What you're facing


This is a short summary of "Explanation of the problem" from the other answer, if you're not sure after reading this, read that.

这是另一个答案中“问题的解释”的简短总结,如果你读完这篇文章还不确定,那就读那篇吧。


The A in AJAX stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example, .send returns immediately and the next statement, return result;, is executed before the function you passed as success callback was even called.

AJAX中的A代表异步。这意味着发送请求(或者更确切地说,接收响应)不在正常执行流程中。在您的示例中,.Send立即返回,并且在您作为成功回调传递的函数被调用之前就执行下一条语句Return Result;。


This means when you're returning, the listener you've defined did not execute yet, which means the value you're returning has not been defined.

这意味着当您返回时,您定义的侦听器尚未执行,这意味着您要返回的值尚未定义。


Here is a simple analogy:

下面是一个简单的类比:


function getFive(){
var a;
setTimeout(function(){
a=5;
},10);
return a;
}

(Fiddle)

(小提琴)


The value of a returned is undefined since the a=5 part has not executed yet. AJAX acts like this, you're returning the value before the server got the chance to tell your browser what that value is.

由于a=5部分尚未执行,因此返回的值未定义。AJAX的行为是这样的,您在服务器有机会告诉您的浏览器该值是什么之前返回值。


One possible solution to this problem is to code re-actively , telling your program what to do when the calculation completed.

此问题的一种可能的解决方案是动态编码,告诉您的程序在计算完成后要做什么。


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're passing getFive an action to perform when it completes, we're telling our code how to react when an event completes (like our AJAX call, or in this case the timeout).

这称为CPS。基本上,我们传递的是getFive完成时要执行的操作,我们告诉我们的代码在事件完成时如何反应(比如我们的AJAX调用,或者在本例中是超时)。


Usage would be:

用法为:


getFive(onComplete);

Which should alert "5" to the screen. (Fiddle).

这应该会向屏幕发出“5”的警报。(小提琴)。


Possible solutions


There are basically two ways how to solve this:

基本上有两种方法可以解决这个问题:



  1. Make the AJAX call synchronous (let’s call it SJAX).

  2. Restructure your code to work properly with callbacks.


1. Synchronous AJAX - Don't do it!!


As for synchronous AJAX, don't do it! Felix's answer raises some compelling arguments about why it's a bad idea. To sum it up, it'll freeze the user's browser until the server returns the response and create a very bad user experience. Here is another short summary taken from MDN on why:

至于同步AJAX,千万别这么做!费利克斯的回答提出了一些令人信服的理由,说明为什么这是一个糟糕的主意。总而言之,它将冻结用户的浏览器,直到服务器返回响应,并造成非常糟糕的用户体验。以下是来自MDN的另一个简短总结,说明原因:



XMLHttpRequest supports both synchronous and asynchronous communications. In general, however, asynchronous requests should be preferred to synchronous requests for performance reasons.


In short, synchronous requests block the execution of code... ...this can cause serious issues...



If you have to do it, you can pass a flag. Here is how:

如果您必须这样做,您可以传递一个旗帜。以下是操作方法:


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. Restructure code


Let your function accept a callback. In the example code foo can be made to accept a callback. We'll be telling our code how to react when foo completes.

让您的函数接受回调。在该示例代码中,可以使foo接受回调。我们将告诉我们的代码在foo完成时如何反应。


So:

所以:


var result = foo();
// Code that depends on `result` goes here

Becomes:

变成:


foo(function(result) {
// Code that depends on `result`
});

Here we passed 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 this sort of callback design is done, check Felix's answer.

有关如何进行这种回调设计的更多详细信息,请查看Felix的回答。


Now, let's define foo itself to act accordingly

现在,让我们定义foo本身以采取相应的行动


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();
}

(fiddle)

(小提琴)


We have now made our foo function accept an action to run when the AJAX completes successfully. We can extend this further by checking if the response status is not 200 and acting accordingly (create a fail handler and such). Effectively it is solving our issue.

现在,我们已经让foo函数接受当AJAX成功完成时要运行的操作。我们可以通过检查响应状态是否不是200并采取相应的操作(创建失败处理程序等)来进一步扩展。实际上,它正在解决我们的问题。


If you're still having a hard time understanding this, read the AJAX getting started guide at MDN.

如果您仍然很难理解这一点,请阅读MDN上的AJAX入门指南。



XMLHttpRequest 2 (first of all, read the answers from Benjamin Gruenbaum and Felix Kling)

XMLHttpRequest 2(首先,阅读Benjamin Gruenbaum和Felix Kling的回答)


If you don't use jQuery and want a nice short XMLHttpRequest 2 which works in the modern browsers and also in the mobile browsers, I suggest to use it this way:

如果您不使用jQuery,而想要一个在现代浏览器和移动浏览器中都能工作的短XMLHttpRequest2,我建议您这样使用它:


function ajax(a, b, c){ // URL, callback, just a placeholder
c = new XMLHttpRequest;
c.open('GET', a);
c.onload = b;
c.send()
}

As you can see:

如您所见:



  1. It's shorter than all other functions Listed.

  2. The callback is set directly (so no extra unnecessary closures).

  3. It uses the new onload (so you don't have to check for readystate && status)

  4. There are some other situations, which I don't remember, that make the XMLHttpRequest 1 annoying.


There are two ways to get the response of this Ajax call (three using the XMLHttpRequest var name):

有两种方法可以获得此AJAX调用的响应(三种使用XMLHttpRequestvar名称):


The simplest:

最简单的:


this.response

Or if for some reason you bind() the callback to a class:

或者,如果出于某种原因将回调绑定()到一个类:


e.target.response

Example:

示例:


function callback(e){
console.log(this.response);
}
ajax('URL', callback);

Or (the above one is better anonymous functions are always a problem):

或者(上面的一个更好,匿名函数总是一个问题):


ajax('URL', function(e){console.log(this.response)});

Nothing easier.

没有比这更容易的了。


Now some people will probably say that it's better to use onreadystatechange or the even the XMLHttpRequest variable name. That's wrong.

现在,有些人可能会说,最好使用onreadystatechange,甚至使用XMLHttpRequest变量名。这是不对的。


Check out XMLHttpRequest advanced features.

了解XMLHttpRequest高级功能。


It supported all *modern browsers. And I can confirm as I have been using this approach since XMLHttpRequest 2 was created. I never had any type of problem in any browsers I used.

它支持所有*现代浏览器。我可以证实,自从XMLHttpRequest2创建以来,我一直在使用这种方法。在我使用的任何浏览器中,我从未遇到过任何类型的问题。


onreadystatechange is only useful if you want to get the headers on state 2.

OnReadyState Change只有在您想要获取状态2上的标头时才有用。


Using the XMLHttpRequest variable name is another big error as you need to execute the callback inside the onload/oreadystatechange closures, or else you lost it.

使用XMLHttpRequest变量名是另一个大错误,因为您需要在onLoad/oreadystatechange闭包内执行回调,否则就会丢失。




Now if you want something more complex using POST and FormData you can easily extend this function:

现在,如果您希望使用POST和FormData执行更复杂的操作,则可以轻松扩展此函数:


function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder
c = new XMLHttpRequest;
c.open(e||'get', a);
c.onload = b;
c.send(d||null)
}

Again ... it's a very short function, but it does GET and POST.

再一次..。这是一个非常短的函数,但它确实具有GET和POST功能。


Examples of usage:

用法示例:


x(url, callback); // By default it's GET so no need to set
x(url, callback, 'post', {'key': 'val'}); // No need to set POST data

Or pass a full form element (document.getElementsByTagName('form')[0]):

或传递完整的表单元素(Docent.getElementsByTagName(‘Form’)[0]):


var fd = new FormData(form);
x(url, callback, 'post', fd);

Or set some custom values:

或设置一些自定义值:


var fd = new FormData();
fd.append('key', 'val')
x(url, callback, 'post', fd);

As you can see, I didn't implement sync... it's a bad thing.

如你所见,我没有实现同步...这是一件坏事。


Having said that ... why don't we do it the easy way?

话虽如此..。我们为什么不用简单的方法来做呢?




As mentioned in the comment, the use of error && synchronous does completely break the point of the answer. Which is a nice short way to use Ajax in the proper way?

正如评论中提到的,使用Error&&Synchronous确实完全打破了答案的要点。哪种方式是正确使用AJAX的捷径?


Error handler

错误处理程序


function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder
c = new XMLHttpRequest;
c.open(e||'get', a);
c.onload = b;
c.onerror = error;
c.send(d||null)
}

function error(e){
console.log('--Error--', this.type);
console.log('this: ', this);
console.log('Event: ', e)
}
function displayAjax(e){
console.log(e, this);
}
x('WRONGURL', displayAjax);

In the above script, you have an error handler which is statically defined, so it does not compromise the function. The error handler can be used for other functions too.

在上面的脚本中,您有一个静态定义的错误处理程序,因此它不会损害函数。错误处理程序也可以用于其他功能。


But to really get out an error, the only way is to write a wrong URL in which case every browser throws an error.

但要真正消除错误,唯一的方法是编写一个错误的URL,在这种情况下,每个浏览器都会抛出一个错误。


Error handlers are maybe useful if you set custom headers, set the responseType to blob array buffer, or whatever...

如果设置自定义头、将响应类型设置为BLOB数组缓冲区或其他任何设置,错误处理程序可能会很有用……


Even if you pass 'POSTAPAPAP' as the method it won't throw an error.

即使您将‘POSTAPAPAP’作为方法传递,它也不会抛出错误。


Even if you pass 'fdggdgilfdghfldj' as formdata it won't throw an error.

即使您将‘fdggdgilfdghfldj’作为formdata传递,它也不会抛出错误。


In the first case the error is inside the displayAjax() under this.statusText as Method not Allowed.

在第一种情况下,错误出现在this.statusText下的displayAJAX()中,因为不允许使用该方法。


In the second case, it simply works. You have to check at the server side if you passed the right post data.

在第二种情况下,它简单地奏效了。你必须在服务器端检查你是否传递了正确的POST数据。


Cross-domain not allowed throws an error automatically.

不允许跨域会自动抛出错误。


In the error response, there aren't any error codes.

在错误响应中,没有任何错误代码。


There is only the this.type which is set to error.

只有this.type设置为Error。


Why add an error handler if you totally don't have any control over errors?
Most of the errors are returned inside this in the callback function displayAjax().

如果您完全无法控制错误,为什么还要添加错误处理程序?大多数错误都在回调函数displayAJAX()中的这个函数中返回。


So: There isn't any need for error checks if you're able to copy and paste the URL properly. ;)

因此:如果您能够正确复制和粘贴URL,则不需要进行任何错误检查。;)


PS: As the first test I wrote x('x', displayAjax)..., and it totally got a response...??? So I checked the folder where the HTML is located, and there was a file called 'x.xml'. So even if you forget the extension of your file XMLHttpRequest 2 WILL FIND IT. I LOL'd

PS:作为第一个测试,我编写了x(‘x’,displayAJAX)...,它完全得到了响应...?所以我检查了HTML所在的文件夹,发现有一个名为‘x.xml’的文件。因此,即使您忘记了文件的扩展名,XMLHttpRequest2也会找到它。我笑了




Read a file synchronous

同步读取文件


Don't do that.

别干那事。


If you want to block the browser for a while load a nice big .txt file synchronous.

如果您想暂时阻止浏览器,请同步加载一个很大的.txt文件。


function omg(a, c){ // URL
c = new XMLHttpRequest;
c.open('GET', a, true);
c.send();
return c; // Or c.response
}

Now you can do

现在你可以做


 var res = omg('thisIsGonnaBlockThePage.txt');

There is no other way to do this in a non-asynchronous way. (Yeah, with setTimeout loop... but seriously?)

没有其他方法可以以非异步方式完成此操作。(是的,使用setTimeout循环...但说真的?)


Another point is... if you work with APIs or just your own list's files or whatever you always use different functions for each request...

另外一点是..。如果您使用API或您自己的列表文件或其他任何东西,您总是为每个请求使用不同的函数……


Only if you have a page where you load always the same XML/JSON or whatever you need only one function. In that case, modify a little the Ajax function and replace b with your special function.

只有当您的页面加载始终相同的XML/JSON或其他内容时,您只需要一个函数。在这种情况下,稍微修改一下AJAX函数,并用您的特殊函数替换b。




The functions above are for basic use.

以上功能仅供基本使用。


If you want to extend the function...

如果您想要扩展该函数...


Yes, you can.

可以,停那儿吧。


I'm using a lot of APIs and one of the first functions I integrate into every HTML page is the first Ajax function in this answer, with GET only...

我使用了很多API,我集成到每个HTML页面的第一个函数之一是这个答案中的第一个AJAX函数,其中只有Get...


But you can do a lot of stuff with XMLHttpRequest 2:

但是您可以使用XMLHttpRequest2做很多事情:


I made a download manager (using ranges on both sides with resume, filereader, and filesystem), various image resizers converters using canvas, populate web SQL databases with base64images and much more...

我做了一个下载管理器(使用带简历、文件阅读器和文件系统的两端的范围),使用Canvas的各种图像大小转换器,用base 64图像填充Web SQL数据库等等……


But in these cases you should create a function only for that purpose... sometimes you need a blob, array buffers, you can set headers, override mimetype and there is a lot more...

但在这些情况下,您应该只为该目的创建一个函数...有时你需要一个BLOB,数组缓冲区,你可以设置标题,覆盖MIMETYPE,还有更多的东西……


But the question here is how to return an Ajax response... (I added an easy way.)

但这里的问题是如何返回AJAX响应……(我添加了一种简单的方法。)



If you're using promises, this answer is for you.


This means AngularJS, jQuery (with deferred), native XHR's replacement (fetch), Ember.js, Backbone.js's save or any Node.js library that returns promises.

这意味着AngularJS、jQuery(带延迟)、原生XHR的替换(FETCH)、Ember.js、Backbone.js的保存或任何返回承诺的Node.js库。


Your code should be something along the lines of this:

您的代码应该是这样的:


function foo() {
var data;
// Or $.get(...).then, or request(...).then, or query(...).then
fetch("/echo/json").then(function(response){
data = response.json();
});
return data;
}

var result = foo(); // 'result' is always undefined no matter what.

Felix Kling did a fine job writing an answer for people using jQuery with callbacks for Ajax. I have an answer for native XHR. This answer is for generic usage of promises either on the frontend or backend.

Felix Kling非常出色地为使用带有AJAX回调的jQuery的用户编写了答案。我有一个关于原生XHR的答案。这个答案适用于承诺在前端或后端的通用用法。




The core issue


The JavaScript concurrency model in the browser and on the server with Node.js/io.js is asynchronous and reactive.

浏览器和带有Node.js/io.js的服务器上的JavaScript并发模型是异步的和被动的。


Whenever you call a method that returns a promise, the then handlers are always executed asynchronously - that is, after the code below them that is not in a .then handler.

每当您调用返回Promise的方法时,Then处理程序总是被异步执行--即,在它们下面不在.Then处理程序中的代码之后执行。


This means when you're returning data the then handler you've defined did not execute yet. This in turn means that the value you're returning has not been set to the correct value in time.

这意味着当您返回数据时,您定义的THEN处理程序尚未执行。这又意味着您返回的值没有及时设置为正确的值。


Here is a simple analogy for the issue:

以下是这个问题的一个简单类比:




    function getFive(){
var data;
setTimeout(function(){ // Set a timer for one second in the future
data = 5; // After a second, do this
}, 1000);
return data;
}
document.body.innerHTML = getFive(); // `undefined` here and not 5




The value of data is undefined since the data = 5 part has not executed yet. It will likely execute in a second, but by that time it is irrelevant to the returned value.

数据的值未定义,因为数据=5部分尚未执行。它可能会在一秒钟内执行,但到那时它就与返回值无关了。


Since the operation did not happen yet (Ajax, server call, I/O, and timer) you're returning the value before the request got the chance to tell your code what that value is.

因为操作还没有发生(AJAX、服务器调用、I/O和计时器),所以您在请求有机会告诉您的代码该值是什么之前返回值。


One possible solution to this problem is to code re-actively, telling your program what to do when the calculation completed. Promises actively enable this by being temporal (time-sensitive) in nature.

此问题的一种可能的解决方案是动态编码,告诉您的程序在计算完成后要做什么。承诺在本质上是暂时的(对时间敏感的),从而积极地实现这一点。


Quick recap on promises


A Promise is a value over time. Promises have state. They start as pending with no value and can settle to:

承诺是随着时间的推移而产生的价值。承诺是有状态的。它们开始时是挂起的,没有任何价值,可以解决以下问题:



  • fulfilled meaning that the computation completed successfully.

  • rejected meaning that the computation failed.


A promise can only change states once after which it will always stay at the same state forever. You can attach then handlers to promises to extract their value and handle errors. then handlers allow chaining of calls. Promises are created by using APIs that return them. For example, the more modern Ajax replacement fetch or jQuery's $.get return promises.

一个承诺只能改变一次状态,之后它将永远保持在同一状态。您可以将Then处理程序附加到承诺,以提取它们的值并处理错误。然后,处理程序允许调用的链接。承诺是通过使用返回它们的API创建的。例如,更现代的AJAX替代品Fetch或jQuery的$.get返回承诺。


When we call .then on a promise and return something from it - we get a promise for the processed value. If we return another promise we'll get amazing things, but let's hold our horses.

当我们调用一个承诺,然后从它返回一些东西时,我们得到了一个关于处理价值的承诺。如果我们再兑现一次承诺,我们会得到令人惊叹的东西,但让我们按兵不动。


With promises


Let's see how we can solve the above issue with promises. First, let's demonstrate our understanding of promise states from above by using the Promise constructor for creating a delay function:

让我们看看如何用承诺来解决上面的问题。首先,让我们通过使用Promise构造函数创建延迟函数来演示我们从上面对Promise状态的理解:


function delay(ms){ // Takes amount of milliseconds
// Returns a new promise
return new Promise(function(resolve, reject){
setTimeout(function(){ // When the time is up,
resolve(); // change the promise to the fulfilled state
}, ms);
});
}

Now, after we converted setTimeout to use promises, we can use then to make it count:

现在,在我们将setTimeout转换为Use Promise之后,我们可以使用THEN来使其生效:




function delay(ms){ // Takes amount of milliseconds
// Returns a new promise
return new Promise(function(resolve, reject){
setTimeout(function(){ // When the time is up,
resolve(); // change the promise to the fulfilled state
}, ms);
});
}

function getFive(){
// We're RETURNING the promise. Remember, a promise is a wrapper over our value
return delay(100).then(function(){ // When the promise is ready,
return 5; // return the value 5. Promises are all about return values
})
}
// We _have_ to wrap it like this in the call site, and we can't access the plain value
getFive().then(function(five){
document.body.innerHTML = five;
});




Basically, instead of returning a value which we can't do because of the concurrency model - we're returning a wrapper for a value that we can unwrap with then. It's like a box you can open with then.

基本上,我们不是返回一个因并发模型而无法执行的值,而是返回一个值的包装器,然后我们可以用它来展开。它就像一个盒子,你可以用它打开。


Applying this


This stands the same for your original API call, you can:

这与您的原始API调用相同,您可以:


function foo() {
// RETURN the promise
return fetch("/echo/json").then(function(response){
return response.json(); // Process it inside the `then`
});
}

foo().then(function(response){
// Access the value inside the `then`
})

So this works just as well. We've learned we can't return values from already asynchronous calls, but we can use promises and chain them to perform processing. We now know how to return the response from an asynchronous call.

因此,这也同样有效。我们已经了解到,我们不能从已有的异步调用返回值,但我们可以使用承诺并链接它们来执行处理。我们现在知道如何从异步调用返回响应。


ES2015 (ES6)


ES6 introduces generators which are functions that can return in the middle and then resume the point they were at. This is typically useful for sequences, for example:

ES6引入了生成器,这些生成器是可以在中间返回然后恢复到它们所在的点的函数。这通常对序列有用,例如:


function* foo(){ // Notice the star. This is ES6, so new browsers, Nodes.js, and io.js only
yield 1;
yield 2;
while(true) yield 3;
}

Is a function that returns an iterator over the sequence 1,2,3,3,3,3,.... which can be iterated. While this is interesting on its own and opens room for a lot of possibility, there is one particular interesting case.

是一个函数,它返回序列1、2、3、3、3、...上的迭代器。这是可以迭代的。虽然这本身很有趣,并为许多可能性打开了空间,但有一个特别有趣的案例。


If the sequence we're producing is a sequence of actions rather than numbers - we can pause the function whenever an action is yielded and wait for it before we resume the function. So instead of a sequence of numbers, we need a sequence of future values - that is: promises.

如果我们生成的序列是动作序列而不是数字序列--我们可以在动作产生时暂停该函数,并在恢复该函数之前等待它。因此,我们需要的不是一个数字序列,而是一个未来值序列--也就是:承诺。


This somewhat a tricky, but very powerful trick let’s us write asynchronous code in a synchronous manner. There are several "runners" that do this for you. Writing one is a short few lines of code, but it is beyond the scope of this answer. I'll be using Bluebird's Promise.coroutine here, but there are other wrappers like co or Q.async.

这在某种程度上是一个棘手但非常强大的技巧,让我们以同步的方式编写异步代码。有几个“跑步者”可以帮你做到这一点。编写一段代码只需几行代码,但这超出了本答案的范围。我将在这里使用Bluebird的Promise.Coroutine,但还有其他包装器,如co或Q.async。


var foo = coroutine(function*(){
var data = yield fetch("/echo/json"); // Notice the yield
// The code here only executes _after_ the request is done
return data.json(); // 'data' is defined
});

This method returns a promise itself, which we can consume from other coroutines. For example:

该方法返回一个Promise本身,我们可以从其他协程中使用它。例如:


var main = coroutine(function*(){
var bar = yield foo(); // Wait our earlier coroutine. It returns a promise
// The server call is done here, and the code below executes when done
var baz = yield fetch("/api/users/" + bar.userid); // Depends on foo's result
console.log(baz); // Runs after both requests are done
});
main();

ES2016 (ES7)


In ES7, this is further standardized. There are several proposals right now, but in all of them you can await promise. This is just "sugar" (nicer syntax) for the ES6 proposal above by adding the async and await keywords. Making the above example:

在ES7中,这一点进一步标准化。目前有几个提案,但在所有提案中,你都可以等待承诺。这只是通过添加Async和AWait关键字对上面的ES6提案进行“糖化”(更好的语法)。举个上面的例子:


async function foo(){
var data = await fetch("/echo/json"); // Notice the await
// code here only executes _after_ the request is done
return data.json(); // 'data' is defined
}

It still returns a promise just the same :)

它仍然返回相同的承诺:)



You are using Ajax incorrectly. The idea is not to have it return anything, but instead hand off the data to something called a callback function, which handles the data.

您错误地使用了AJAX。这个想法不是让它返回任何东西,而是将数据传递给一个称为回调函数的东西,该函数处理数据。



That is:

即:



function handleData( responseData ) {

// Do what you want with the data
console.log(responseData);
}

$.ajax({
url: "hi.php",
...
success: function ( data, status, XHR ) {
handleData(data);
}
});


Returning anything in the submit handler will not do anything. You must instead either hand off the data, or do what you want with it directly inside the success function.

在提交处理程序中返回任何内容都不会有任何效果。相反,您必须在Success函数中传递数据,或者直接对其执行您想要的操作。



I will answer with a horrible-looking, hand-drawn comic. The second image is the reason why result is undefined in your code example.

我会用一幅看起来很糟糕的手绘漫画来回答。第二个图像是代码示例中未定义结果的原因。



enter image description here



The simplest solution is to create a JavaScript function and call it for the Ajax success callback.

最简单的解决方案是创建一个JavaScript函数并调用它来实现AJAX成功回调。


function callServerAsync(){
$.ajax({
url: '...',
success: function(response) {

successCallback(response);
}
});
}

function successCallback(responseObj){
// Do something like read the response and show data
alert(JSON.stringify(responseObj)); // Only applicable to a JSON response
}

function foo(callback) {

$.ajax({
url: '...',
success: function(response) {
return callback(null, response);
}
});
}

var result = foo(function(err, result){
if (!err)
console.log(result);
});


Angular 1


People who are using AngularJS, can handle this situation using promises.

使用AngularJS的人可以通过承诺来处理这种情况。


Here it says,

这里写着,



Promises can be used to unnest asynchronous functions and allows one to chain multiple functions together.



You can find a nice explanation here also.

你也可以在这里找到一个很好的解释。


An example found in documentation mentioned below.

下面提到的文档中提供了一个示例。


  promiseB = promiseA.then(
function onSuccess(result) {
return result + 1;
}
,function onError(err) {
// Handle error
}
);

// promiseB will be resolved immediately after promiseA is resolved
// and its value will be the result of promiseA incremented by 1.

Angular 2 and later


In Angular 2 with look at the following example, but its recommended to use observables with Angular 2.

在角度2中,请看下面的例子,但建议使用角度为2的可观测对象。


 search(term: string) {
return this.http
.get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
.map((response) => response.json())
.toPromise();
}

You can consume that in this way,

你可以用这种方式消费它,


search() {
this.searchService.search(this.searchField.value)
.then((result) => {
this.result = result.artists.items;
})
.catch((error) => console.error(error));
}

See the original post here. But TypeScript does not support native ES6 Promises, if you want to use it, you might need plugin for that.

请看这里的原文。但是TypeScrip不支持原生ES6承诺,如果你想使用它,你可能需要插件来实现。


Additionally, here is the promises specification.

此外,以下是Promises规范。



Most of the answers here give useful suggestions for when you have a single async operation, but sometimes, this comes up when you need to do an asynchronous operation for each entry in an array or other list-like structure. The temptation is to do this:

对于何时执行单个异步操作,这里的大多数答案都给出了有用的建议,但有时,当您需要为数组或其他类似列表的结构中的每个条目执行异步操作时,就会出现这种情况。这样做很有诱惑力:


// WRONG
var results = [];
theArray.forEach(function(entry) {
doSomethingAsync(entry, function(result) {
results.push(result);
});
});
console.log(results); // E.g., using them, returning them, etc.

Example:

示例:




// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
doSomethingAsync(entry, function(result) {
results.push(result);
});
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}

.as-console-wrapper { max-height: 100% !important; }




The reason that doesn't work is that the callbacks from doSomethingAsync haven't run yet by the time you're trying to use the results.

这不起作用的原因是,当您尝试使用结果时,doSomethingAsync的回调还没有运行。


So, if you have an array (or list of some kind) and want to do async operations for each entry, you have two options: Do the operations in parallel (overlapping), or in series (one after another in sequence).

因此,如果您有一个数组(或某种类型的列表),并且希望对每个条目执行异步操作,则有两种选择:并行(重叠)或串联(按顺序依次)。


Parallel


You can start all of them and keep track of how many callbacks you're expecting, and then use the results when you've gotten that many callbacks:

您可以启动所有回调并跟踪您预期的回调次数,然后在收到这么多回调时使用结果:


var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
console.log("Results:", results); // E.g., using the results
}
});
});

Example:

示例:




var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
console.log("Results:", JSON.stringify(results)); // E.g., using the results
}
});
});

function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}

.as-console-wrapper { max-height: 100% !important; }




(We could do away with expecting and just use results.length === theArray.length, but that leaves us open to the possibility that theArray is changed while the calls are outstanding...)

(我们可以不使用预期结果,而只使用结果。长度==theArray.long,但这为我们提供了一种可能性,即在调用未完成时,theArray可能会被更改...)


Notice how we use the index from forEach to save the result in results in the same position as the entry it relates to, even if the results arrive out of order (since async calls don't necessarily complete in the order in which they were started).

请注意,我们如何使用forEach中的索引将结果保存在与其相关的条目相同的位置,即使结果无序到达(因为异步调用不一定以它们启动的顺序完成)。


But what if you need to return those results from a function? As the other answers have pointed out, you can't; you have to have your function accept and call a callback (or return a Promise). Here's a callback version:

但是,如果您需要从函数返回这些结果,该怎么办呢?正如其他答案所指出的,您不能;您必须让您的函数接受并调用回调(或返回承诺)。以下是回调版本:


function doSomethingWith(theArray, callback) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
callback(results);
}
});
});
}
doSomethingWith(theArray, function(results) {
console.log("Results:", results);
});

Example:

示例:




function doSomethingWith(theArray, callback) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
callback(results);
}
});
});
}
doSomethingWith([1, 2, 3], function(results) {
console.log("Results:", JSON.stringify(results));
});

function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}

.as-console-wrapper { max-height: 100% !important; }




Or here's a version returning a Promise instead:

或者,下面是一个返回承诺的版本:


function doSomethingWith(theArray) {
return new Promise(function(resolve) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
resolve(results);
}
});
});
});
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});

Of course, if doSomethingAsync passed us errors, we'd use reject to reject the promise when we got an error.)

当然,如果doSomethingAsync传递给我们错误,当我们收到错误时,我们会使用Reject来拒绝承诺。)


Example:

示例:




function doSomethingWith(theArray) {
return new Promise(function(resolve) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
resolve(results);
}
});
});
});
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", JSON.stringify(results));
});

function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}

.as-console-wrapper { max-height: 100% !important; }




(Or alternately, you could make a wrapper for doSomethingAsync that returns a promise, and then do the below...)

(或者,您也可以为doSomethingAsync制作一个返回承诺的包装器,然后执行以下操作...)


If doSomethingAsync gives you a Promise, you can use Promise.all:

如果doSomethingAsync给了您承诺,则可以使用Promise.all:


function doSomethingWith(theArray) {
return Promise.all(theArray.map(function(entry) {
return doSomethingAsync(entry);
}));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});

If you know that doSomethingAsync will ignore a second and third argument, you can just pass it directly to map (map calls its callback with three arguments, but most people only use the first most of the time):

如果您知道doSomethingAsync会忽略第二个和第三个参数,您可以直接将其传递给map(map使用三个参数调用其回调,但大多数人在大多数情况下只使用第一个参数):


function doSomethingWith(theArray) {
return Promise.all(theArray.map(doSomethingAsync));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});

Example:

示例:




function doSomethingWith(theArray) {
return Promise.all(theArray.map(doSomethingAsync));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", JSON.stringify(results));
});

function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}

.as-console-wrapper { max-height: 100% !important; }




Note that Promise.all resolves its promise with an array of the results of all of the promises you give it when they are all resolved, or rejects its promise when the first of the promises you give it rejects.

请注意,Promise.All使用您给它的所有承诺的结果数组来解析它的承诺,当它们都被解决时,或者当你给它的第一个承诺被拒绝时,它拒绝它的承诺。


Series


Suppose you don't want the operations to be in parallel? If you want to run them one after another, you need to wait for each operation to complete before you start the next. Here's an example of a function that does that and calls a callback with the result:

假设您不希望这些操作是并行的?如果您想要一个接一个地运行它们,则需要等待每个操作完成后再开始下一个操作。下面是一个执行此操作并使用结果调用回调的函数的示例:


function doSomethingWith(theArray, callback) {
var results = [];
doOne(0);
function doOne(index) {
if (index < theArray.length) {
doSomethingAsync(theArray[index], function(result) {
results.push(result);
doOne(index + 1);
});
} else {
// Done!
callback(results);
}
}
}
doSomethingWith(theArray, function(results) {
console.log("Results:", results);
});

(Since we're doing the work in series, we can just use results.push(result) since we know we won't get results out of order. In the above we could have used results[index] = result;, but in some of the following examples we don't have an index to use.)

(因为我们是按顺序进行工作的,所以我们可以只使用Results.ush(Result),因为我们知道我们不会得到无序的结果。在上面的示例中,我们可以使用RESULTS[INDEX]=RESULT;,但在下面的一些示例中,我们没有使用索引。)


Example:

示例:




function doSomethingWith(theArray, callback) {
var results = [];
doOne(0);
function doOne(index) {
if (index < theArray.length) {
doSomethingAsync(theArray[index], function(result) {
results.push(result);
doOne(index + 1);
});
} else {
// Done!
callback(results);
}
}
}
doSomethingWith([1, 2, 3], function(results) {
console.log("Results:", JSON.stringify(results));
});

function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}

.as-console-wrapper { max-height: 100% !important; }




(Or, again, build a wrapper for doSomethingAsync that gives you a promise and do the below...)

(或者,再一次,为doSomethingAsync构建一个包装器,给你一个承诺,并执行以下操作...)


If doSomethingAsync gives you a Promise, if you can use ES2017+ syntax (perhaps with a transpiler like Babel), you can use an async function with for-of and await:

如果doSomethingAsync给了您一个承诺,如果您可以使用ES2017+语法(可能与Babel这样的代码转换程序一起使用),您可以使用带有for-of和aWait的异步函数:


async function doSomethingWith(theArray) {
const results = [];
for (const entry of theArray) {
results.push(await doSomethingAsync(entry));
}
return results;
}
doSomethingWith(theArray).then(results => {
console.log("Results:", results);
});

Example:

示例:




async function doSomethingWith(theArray) {
const results = [];
for (const entry of theArray) {
results.push(await doSomethingAsync(entry));
}
return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", JSON.stringify(results));
});

function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}

.as-console-wrapper { max-height: 100% !important; }




If you can't use ES2017+ syntax (yet), you can use a variation on the "Promise reduce" pattern (this is more complex than the usual Promise reduce because we're not passing the result from one into the next, but instead gathering up their results in an array):

如果您还不能使用ES2017+语法,您可以使用“Promise Reduce”模式的变体(这比通常的Promise Reduce更复杂,因为我们不是将结果从一个传递到下一个,而是将它们的结果收集到一个数组中):


function doSomethingWith(theArray) {
return theArray.reduce(function(p, entry) {
return p.then(function(results) {
return doSomethingAsync(entry).then(function(result) {
results.push(result);
return results;
});
});
}, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});

Example:

示例:




function doSomethingWith(theArray) {
return theArray.reduce(function(p, entry) {
return p.then(function(results) {
return doSomethingAsync(entry).then(function(result) {
results.push(result);
return results;
});
});
}, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", JSON.stringify(results));
});

function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}

.as-console-wrapper { max-height: 100% !important; }




...which is less cumbersome with ES2015+ arrow functions:

...使用ES2015+箭头功能不会那么麻烦:


function doSomethingWith(theArray) {
return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
results.push(result);
return results;
})), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
console.log("Results:", results);
});

Example:

示例:




function doSomethingWith(theArray) {
return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
results.push(result);
return results;
})), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", JSON.stringify(results));
});

function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}

.as-console-wrapper { max-height: 100% !important; }





Have a look at this example:

看一下这个例子:



var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,$http) {

var getJoke = function(){
return $http.get('http://api.icndb.com/jokes/random').then(function(res){
return res.data.value;
});
}

getJoke().then(function(res) {
console.log(res.joke);
});
});


As you can see getJoke is returning a resolved promise (it is resolved when returning res.data.value). So you wait until the $http.get request is completed and then console.log(res.joke) is executed (as a normal asynchronous flow).

正如您所看到的,getJoke返回一个已解析的承诺(它在返回res.data.value时被解析)。因此,您需要等待$HTTP.GET请求完成,然后再执行sole.log(res.joke)(作为一个普通的异步流)。



This is the plnkr:

这是PLNKR:



http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/

Http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/



ES6 way (async - await)

ES6路(异步等待)



(function(){
async function getJoke(){
let response = await fetch('http://api.icndb.com/jokes/random');
let data = await response.json();
return data.value;
}

getJoke().then((joke) => {
console.log(joke);
});
})();


This is one of the places which two-way data binding or store concept that's used in many new JavaScript frameworks will work great for you...

这是在许多新的JavaScript框架中使用的双向数据绑定或存储概念将非常适合您的地方之一……


So if you are using Angular, React, or any other frameworks which do two-way data binding or store concept, this issue is simply fixed for you, so in easy words, your result is undefined at the first stage, so you have got result = undefined before you receive the data, then as soon as you get the result, it will be updated and get assigned to the new value which response of your Ajax call...

因此,如果您使用的是ANGLE、REACT或任何其他执行双向数据绑定或存储概念的框架,那么这个问题就为您解决了,所以简单地说,您的结果在第一个阶段是未定义的,所以您在接收数据之前就得到了RESULT=UNDEFINED,然后一旦您获得结果,它就会被更新,并被赋给您的AJAX调用的响应的新值...


But how you can do it in pure JavaScript or jQuery for example as you asked in this question?

但是,您如何才能像您在这个问题中所问的那样,用纯JavaScript或jQuery来实现呢?


You can use a callback, promise and recently observable to handle it for you. For example, in promises we have some function like success() or then() which will be executed when your data is ready for you. The same with callback or the subscribe function on an observable.

您可以使用回调、承诺和最近观察来为您处理它。例如,在承诺中,我们有一些函数,如Success()或Then(),它们将在您的数据准备就绪时执行。可观测对象上的回调或订阅函数也是如此。


For example, in your case which you are using jQuery, you can do something like this:

例如,在您使用jQuery的情况下,您可以这样做:


$(document).ready(function(){
function foo() {
$.ajax({url: "api/data", success: function(data){
fooDone(data); // After we have data, we pass it to fooDone
}});
};

function fooDone(data) {
console.log(data); // fooDone has the data and console.log it
};

foo(); // The call happens here
});

For more information, study promises and observables which are newer ways to do this async stuff.

有关更多信息,请研究承诺和可观测数据,它们是实现这种异步化的较新方法。



It's a very common issue we face while struggling with the 'mysteries' of JavaScript. Let me try demystifying this mystery today.

这是我们在与JavaScript的“奥秘”作斗争时面临的一个非常常见的问题。今天让我试着揭开这个神秘的面纱。


Let's start with a simple JavaScript function:

让我们从一个简单的JavaScript函数开始:


function foo(){
// Do something
return 'wohoo';
}

let bar = foo(); // 'bar' is 'wohoo' here

That's a simple synchronous function call (where each line of code is 'finished with its job' before the next one in sequence), and the result is same as expected.

这是一个简单的同步函数调用(其中每一行代码都在序列中的下一行代码之前‘完成了它的作业’),结果与预期相同。


Now let's add a bit of twist, by introducing a little delay in our function, so that all lines of code are not 'finished' in sequence. Thus, it will emulate the asynchronous behavior of the function:

现在,让我们通过在我们的函数中引入一点延迟来增加一点麻烦,这样就不会按顺序“完成”所有代码行。因此,它将模拟函数的异步行为:


function foo(){
setTimeout( ()=> {
return 'wohoo';
}, 1000)
}

let bar = foo() // 'bar' is undefined here

So there you go; that delay just broke the functionality we expected! But what exactly happened? Well, it's actually pretty logical if you look at the code.

这就对了;这个延迟刚刚破坏了我们预期的功能!但到底发生了什么?如果你看一下代码,这实际上是非常合乎逻辑的。


The function foo(), upon execution, returns nothing (thus returned value is undefined), but it does start a timer, which executes a function after 1 second to return 'wohoo'. But as you can see, the value that's assigned to bar is the immediately returned stuff from foo(), which is nothing, i.e., just undefined.

函数foo()在执行时不返回任何内容(因此返回值未定义),但它确实启动了一个计时器,该计时器在1秒后执行一个函数以返回‘woho’。但是正如您所看到的,分配给bar的值是从foo()直接返回的内容,它是Nothing,也就是说,没有定义。


So, how do we tackle this issue?

那么,我们如何解决这个问题呢?


Let's ask our function for a promise.
Promise is really about what it means: it means that the function guarantees you to provide with any output it gets in future. So let's see it in action for our little problem above:

让我们向我们的函数请求一个承诺。Promise实际上是关于它的含义:它意味着该函数保证您将来提供它所获得的任何输出。因此,让我们来看看上面的小问题的实际情况:


function foo(){
return new Promise((resolve, reject) => { // I want foo() to PROMISE me something
setTimeout ( function(){
// Promise is RESOLVED, when the execution reaches this line of code
resolve('wohoo') // After 1 second, RESOLVE the promise with value 'wohoo'
}, 1000 )
})
}

let bar;
foo().then( res => {
bar = res;
console.log(bar) // Will print 'wohoo'
});

Thus, the summary is - to tackle the asynchronous functions like Ajax-based calls, etc., you can use a promise to resolve the value (which you intend to return). Thus, in short you resolve value instead of returning, in asynchronous functions.

因此,总结如下:要处理基于AJAX的调用等异步函数,您可以使用承诺来解析(您想要返回的)值。因此,简而言之,在异步函数中解析值而不是返回。


UPDATE (Promises with async/await)


Apart from using then/catch to work with promises, there exists one more approach. The idea is to recognize an asynchronous function and then wait for the promises to resolve, before moving to the next line of code. It's still just the promises under the hood, but with a different syntactical approach. To make things clearer, you can find a comparison below:

除了使用Then/Catch处理承诺之外,还有一种方法。我们的想法是识别一个异步函数,然后等待承诺得到解析,然后再转到下一行代码。它仍然只是引擎盖下的承诺,但具有不同的语法方法。为了让事情更清楚,你可以找到下面的比较:


then/catch version:


function saveUsers(){
getUsers()
.then(users => {
saveSomewhere(users);
})
.catch(err => {
console.error(err);
})
}

async/await version:


  async function saveUsers(){
try{
let users = await getUsers()
saveSomewhere(users);
}
catch(err){
console.error(err);
}
}


Another approach to return a value from an asynchronous function, is to pass in an object that will store the result from the asynchronous function.

从异步函数返回值的另一种方法是传入一个对象,该对象将存储来自异步函数的结果。



Here is an example of the same:

下面是一个相同的例子:



var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
// some asynchronous operation
$.ajax({
url: '...',
success: function(response) {
result.response = response;
_callback();
}
});
});

async.parallel(asyncTasks, function(){
// result is available after performing asynchronous operation
console.log(result)
console.log('Done');
});


I am using the result object to store the value during the asynchronous operation. This allows the result be available even after the asynchronous job.

在异步操作期间,我使用Result对象来存储值。这使结果即使在异步作业之后也可用。



I use this approach a lot. I would be interested to know how well this approach works where wiring the result back through consecutive modules is involved.

我经常使用这种方法。我想知道这种方法在涉及到通过连续模块连接结果的情况下工作得有多好。



While promises and callbacks work fine in many situations, it is a pain in the rear to express something like:

虽然承诺和回电在许多情况下都很有效,但表达如下内容会让人感到痛苦:



if (!name) {
name = async1();
}
async2(name);


You'd end up going through async1; check if name is undefined or not and call the callback accordingly.

您最终将经历async1;检查名称是否未定义,并相应地调用回调。



async1(name, callback) {
if (name)
callback(name)
else {
doSomething(callback)
}
}

async1(name, async2)


While it is okay in small examples it gets annoying when you have a lot of similar cases and error handling involved.

虽然在小示例中这是可以的,但当涉及到许多类似的案例和错误处理时,就会变得很烦人。



Fibers helps in solving the issue.

纤维有助于解决这个问题。



var Fiber = require('fibers')

function async1(container) {
var current = Fiber.current
var result
doSomething(function(name) {
result = name
fiber.run()
})
Fiber.yield()
return result
}

Fiber(function() {
var name
if (!name) {
name = async1()
}
async2(name)
// Make any number of async calls from here
}


You can checkout the project here.

你可以在这里签下这个项目。



The following example I have written shows how to

我编写的以下示例显示了如何




  • Handle asynchronous HTTP calls;

  • Wait for response from each API call;

  • Use Promise pattern;

  • Use Promise.all pattern to join multiple HTTP calls;



This working example is self-contained. It will define a simple request object that uses the window XMLHttpRequest object to make calls. It will define a simple function to wait for a bunch of promises to be completed.

这个工作示例是自包含的。它将定义一个简单的请求对象,该对象使用窗口XMLHttpRequest对象进行调用。它将定义一个简单的函数来等待一系列承诺的完成。



Context. The example is querying the Spotify Web API endpoint in order to search for playlist objects for a given set of query strings:

上下文。该示例查询Spotify Web API终结点,以便搜索给定查询字符串集的播放列表对象:



[
"search?type=playlist&q=%22doom%20metal%22",
"search?type=playlist&q=Adele"
]


For each item, a new Promise will fire a block - ExecutionBlock, parse the result, schedule a new set of promises based on the result array, that is a list of Spotify user objects and execute the new HTTP call within the ExecutionProfileBlock asynchronously.

对于每个条目,新的Promise将触发一个块ExecutionBlock,解析结果,根据结果数组(即Spotify User对象列表)调度一组新的Promise,并在ExecutionProfileBlock中异步执行新的HTTP调用。



You can then see a nested Promise structure, that lets you spawn multiple and completely asynchronous nested HTTP calls, and join the results from each subset of calls through Promise.all.

然后,您可以看到一个嵌套的Promise结构,它允许您派生多个完全异步的嵌套HTTP调用,并通过Promise.all连接来自每个调用子集的结果。



NOTE
Recent Spotify search APIs will require an access token to be specified in the request headers:

注意:最新的Spotify搜索API需要在请求标头中指定访问令牌:



-H "Authorization: Bearer {your access token}" 


So, you to run the following example you need to put your access token in the request headers:

因此,要运行以下示例,您需要将访问令牌放入请求标头中:





var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
log: function(s) {
document.getElementById("console").innerHTML += s + "<br/>"
}
}

// Simple XMLHttpRequest
// based on https://davidwalsh.name/xmlhttprequest
SimpleRequest = {
call: function(what, response) {
var request;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // Internet Explorer
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
}
catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {}
}
}

// State changes
request.onreadystatechange = function() {
if (request.readyState === 4) { // Done
if (request.status === 200) { // Complete
response(request.responseText)
}
else
response();
}
}
request.open('GET', what, true);
request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken);
request.send(null);
}
}

//PromiseAll
var promiseAll = function(items, block, done, fail) {
var self = this;
var promises = [],
index = 0;
items.forEach(function(item) {
promises.push(function(item, i) {
return new Promise(function(resolve, reject) {
if (block) {
block.apply(this, [item, index, resolve, reject]);
}
});
}(item, ++index))
});
Promise.all(promises).then(function AcceptHandler(results) {
if (done) done(results);
}, function ErrorHandler(error) {
if (fail) fail(error);
});
}; //promiseAll

// LP: deferred execution block
var ExecutionBlock = function(item, index, resolve, reject) {
var url = "https://api.spotify.com/v1/"
url += item;
console.log( url )
SimpleRequest.call(url, function(result) {
if (result) {

var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) {
return item.owner.href;
})
resolve(profileUrls);
}
else {
reject(new Error("call error"));
}
})
}

arr = [
"search?type=playlist&q=%22doom%20metal%22",
"search?type=playlist&q=Adele"
]

promiseAll(arr, function(item, index, resolve, reject) {
console.log("Making request [" + index + "]")
ExecutionBlock(item, index, resolve, reject);
}, function(results) { // Aggregated results

console.log("All profiles received " + results.length);
//console.log(JSON.stringify(results[0], null, 2));

///// promiseall again

var ExecutionProfileBlock = function(item, index, resolve, reject) {
SimpleRequest.call(item, function(result) {
if (result) {
var obj = JSON.parse(result);
resolve({
name: obj.display_name,
followers: obj.followers.total,
url: obj.href
});
} //result
})
} //ExecutionProfileBlock

promiseAll(results[0], function(item, index, resolve, reject) {
//console.log("Making request [" + index + "] " + item)
ExecutionProfileBlock(item, index, resolve, reject);
}, function(results) { // aggregated results
console.log("All response received " + results.length);
console.log(JSON.stringify(results, null, 2));
}

, function(error) { // Error
console.log(error);
})

/////

},
function(error) { // Error
console.log(error);
});

<div id="console" />





I have extensively discussed this solution here.

我在这里广泛地讨论了这个解决方案。



The short answer is, you have to implement a callback like this:

简短的答案是,您必须实现如下回调:


function callback(response) {
// Here you can do what ever you want with the response object.
console.log(response);
}

$.ajax({
url: "...",
success: callback
});



JavaScript is single threaded.



The browser can be divided into three parts:

浏览器可以分为三个部分:



  1. Event Loop



  2. Web API



  3. Event Queue




The event loop runs for forever, i.e., kind of an infinite loop. The event queue is where all your functions are pushed on some event (example: click).

事件循环永远运行,即一种无限循环。事件队列是您的所有函数在某个事件上被推送的位置(例如:单击)。


This is one by one carried out of queue and put into the event loop which executes this function and prepares itself for the next one after the first one is executed. This means execution of one function doesn't start until the function before it in the queue is executed in the event loop.

这是一个接一个地从队列中执行,并放入执行此函数的事件循环中,并在第一个函数执行后为下一个函数做好准备。这意味着,直到在事件循环中执行队列中该函数之前的函数时,才会开始执行一个函数。


Now let us think we pushed two functions in a queue. One is for getting a data from the server and another utilises that data. We pushed the serverRequest() function in the queue first and then the utiliseData() function. The serverRequest function goes in the event loop and makes a call to server as we never know how much time it will take to get data from server, so this process is expected to take time and so we busy our event loop thus hanging our page.

现在让我们假设我们在一个队列中推入了两个函数。一个用于从服务器获取数据,另一个用于利用该数据。我们首先将serverRequest()函数推入队列,然后将utiliseData()函数推入队列。ServerRequest函数进入事件循环并调用服务器,因为我们永远不知道从服务器获取数据需要多长时间,所以这个过程预计会花费时间,因此我们忙于事件循环,从而挂起了页面。


That's where Web API come into the role. It takes this function from the event loop and deals with the server making the event loop free, so that we can execute the next function from the queue.

这就是Web API发挥作用的地方。它从事件循环中获取此函数,并处理服务器释放事件循环,以便我们可以执行队列中的下一个函数。


The next function in the queue is utiliseData() which goes in the loop, but because of no data available, it goes to waste and execution of the next function continues until the end of the queue. (This is called Async calling, i.e., we can do something else until we get data.)

队列中的下一个函数是utiliseData(),它进入循环,但由于没有可用的数据,它会被浪费,下一个函数的执行将继续,直到队列结束。(这被称为异步调用,即我们可以做其他事情,直到我们得到数据。)


Let us suppose our serverRequest() function had a return statement in code. When we get back data from the server Web API, it will push it in the queue at the end of queue.

让我们假设我们的serverRequest()函数在代码中有一条返回语句。当我们从服务器Web API取回数据时,它将把数据推入队列末尾的队列中。


As it gets pushed at the end of the queue, we cannot utilise its data as there isn't any function left in our queue to utilise this data. Thus it is not possible to return something from the async call.

当它在队列的末尾被推送时,我们不能利用它的数据,因为我们的队列中没有留下任何函数来利用这些数据。因此,不可能从异步调用中返回某些内容。


Thus the solution to this is callback or promise.

因此,解决这一问题的办法是回调或承诺。



We give our function (function utilising data returned from the server) to a function calling the server.

我们将我们的函数(使用从服务器返回的数据的函数)交给调用服务器的函数。


Callback


function doAjax(callbackFunc, method, url) {
var xmlHttpReq = new XMLHttpRequest();
xmlHttpReq.open(method, url);
xmlHttpReq.onreadystatechange = function() {

if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) {
callbackFunc(xmlHttpReq.responseText);
}
}
xmlHttpReq.send(null);
}

In my code it is called as:

在我的代码中,它被称为:


function loadMyJson(categoryValue){
if(categoryValue === "veg")
doAjax(print, "GET", "http://localhost:3004/vegetables");
else if(categoryValue === "fruits")
doAjax(print, "GET", "http://localhost:3004/fruits");
else
console.log("Data not found");
}

JavaScript.info callback

JavaScript.info回调



2017 answer: you can now do exactly what you want in every current browser and Node.js


This is quite simple:

这很简单:



  • Return a Promise

  • Use the 'await', which will tell JavaScript to await the promise to be resolved into a value (like the HTTP response)

  • Add the 'async' keyword to the parent function


Here's a working version of your code:

以下是您的代码的工作版本:


(async function(){

var response = await superagent.get('...')
console.log(response)

})()

await is supported in all current browsers and Node.js 8

当前所有浏览器和Node.js 8都支持等待



You can use this custom library (written using Promise) to make a remote call.

您可以使用这个定制库(使用Promise编写)进行远程调用。



function $http(apiConfig) {
return new Promise(function (resolve, reject) {
var client = new XMLHttpRequest();
client.open(apiConfig.method, apiConfig.url);
client.send();
client.onload = function () {
if (this.status >= 200 && this.status < 300) {
// Performs the function "resolve" when this.status is equal to 2xx.
// Your logic here.
resolve(this.response);
}
else {
// Performs the function "reject" when this.status is different than 2xx.
reject(this.statusText);
}
};
client.onerror = function () {
reject(this.statusText);
};
});
}


Simple usage example:

简单用法示例:



$http({
method: 'get',
url: 'google.com'
}).then(function(response) {
console.log(response);
}, function(error) {
console.log(error)
});


Another solution is to execute code via the sequential executor nsynjs.

另一种解决方案是通过顺序执行器nsynjs执行代码。


If the underlying function is promisified


nsynjs will evaluate all promises sequentially, and put the promise result into the data property:

Nsynjs将按顺序评估所有承诺,并将承诺结果放入data属性中:




function synchronousCode() {

var getURL = function(url) {
return window.fetch(url).data.text().data;
};

var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js';
console.log('received bytes:',getURL(url).length);

};

nsynjs.run(synchronousCode,{},function(){
console.log('synchronousCode done');
});

<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>




If the underlying function is not promisified


Step 1. Wrap the function with a callback into the nsynjs-aware wrapper (if it has a promisified version, you can skip this step):

步骤1.使用回调将函数包装到支持nsynjs的包装器中(如果它有一个简化版本,您可以跳过这一步):


var ajaxGet = function (ctx,url) {
var res = {};
var ex;
$.ajax(url)
.done(function (data) {
res.data = data;
})
.fail(function(e) {
ex = e;
})
.always(function() {
ctx.resume(ex);
});
return res;
};
ajaxGet.nsynjsHasCallback = true;

Step 2. Put synchronous logic into function:

步骤2.将同步逻辑放入函数中:


function process() {
console.log('got data:', ajaxGet(nsynjsCtx, "data/file1.json").data);
}

Step 3. Run function in synchronous manner via nsynjs:

Step 3.通过nsynjs同步运行函数:


nsynjs.run(process,this,function () {
console.log("synchronous function finished");
});

Nsynjs will evaluate all operators and expressions step-by-step, pausing execution in case if the result of some slow function is not ready.

Nsynjs将一步一步地计算所有运算符和表达式,如果某个速度较慢的函数的结果尚未准备好,则暂停执行。


More examples are here.

这里有更多的例子。



ECMAScript 6 has 'generators' which allow you to easily program in an asynchronous style.

ECMAScript6有‘生成器’,允许您轻松地以异步风格编程。



function* myGenerator() {
const callback = yield;
let [response] = yield $.ajax("https://stackoverflow.com", {complete: callback});
console.log("response is:", response);

// examples of other things you can do
yield setTimeout(callback, 1000);
console.log("it delayed for 1000ms");
while (response.statusText === "error") {
[response] = yield* anotherGenerator();
}
}


To run the above code you do this:

要运行上面的代码,您需要执行以下操作:



const gen = myGenerator(); // Create generator
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function


If you need to target browsers that don't support ES6 you can run the code through Babel or closure-compiler to generate ECMAScript 5.

如果您需要针对不支持ES6的浏览器,您可以通过Babel或闭包编译器运行代码来生成ECMASSIPT5。



The callback ...args are wrapped in an array and destructured when you read them so that the pattern can cope with callbacks that have multiple arguments. For example with node fs:

回调参数被包装在一个数组中,并在您读取它们时进行结构化处理,以便该模式可以处理具有多个参数的回调。例如,对于节点文件系统:



const [err, data] = yield fs.readFile(filePath, "utf-8", callback);


1. A first stumbling step


As for many others, my encounter with asynchronous calls was puzzling
at first.

I don't remember the details, but I may have tried something like:

对于其他许多人,我遇到的异步调用一开始是令人费解的。我不记得细节了,但我可能试过这样的方法:




let result;

$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/1',
success: function (response) {
console.log('\nInside $.ajax:');
console.log(response);
result = response;
}
});

console.log('Finally, the result: ' + result);

.as-console-wrapper { max-height: 100% !important; top: 0; }

<script src=
"https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>




Whoops! The output of the line
console.log('Finally, the result: ' + result);
which I thought would be printed last, is actually printed before
the other output! – And it doesn't contain the result: it just
prints undefined.
1

How come?

哎呀!我原以为最后打印的那一行console.log(‘Finally,the Result:’+Result)的输出实际上是在其他输出之前打印的!-而且它不包含结果:它只是打印未定义的结果。1怎么会这样?


A helpful insight

有益的洞察力


I distinctly remember my first aha! moment on how to understand
asynchronous calls.

It was this comment saying:

you actually don't want to get the data out of a callback;

you want to get your data-needing action into the callback!

2

This is obvious in the example above.

But is it still possible to write code after the asynchronous call
that deals with the response once it has completed?

我清楚地记得我的第一次啊哈!关于如何理解异步调用的时刻。这条评论是这样说的:您实际上不想从回调中获取数据;您希望将需要数据的操作放入回调中!2这在上面的示例中很明显。但是,是否仍然可以在异步调用完成后编写处理响应的代码呢?


2. Plain JavaScript and a callback function


The answer is yes! – It is possible.

One alternative is the use of a callback function in a
continuation-passing style:
3

答案是肯定的!-这是可能的。一种替代方法是使用延续传递样式的回调函数:3




const url = 'https://jsonplaceholder.typicode.com/todos/2';

function asynchronousCall (callback) {
const request = new XMLHttpRequest();
request.open('GET', url);
request.send();
request.onload = function () {
if (request.readyState === request.DONE) {
console.log('The request is done. Now calling back.');
callback(request.responseText);
}
};
}

asynchronousCall(function (result) {
console.log('This is the start of the callback function. Result:');
console.log(result);
console.log('The callback function finishes on this line. THE END!');
});

console.log('LAST in the code, but executed FIRST!');

.as-console-wrapper { max-height: 100% !important; top: 0; }




Note how the function asynchronousCall is void.
It returns nothing.
Instead, by calling asynchronousCall with an anonymous callback
function (asynchronousCall(function (result) {...), this function
executes the desired actions on the result, but only after the
request has completed – when the responseText is available.

请注意函数asynousCall是如何为空的。它不返回任何内容。相反,通过使用匿名回调函数(asynousCall(Function(Result){...))调用asynousCall,该函数对结果执行所需的操作,但仅在请求完成后-当响应文本可用时。


Running the above snippet shows how I will probably not want to write
any code after the asynchronous call (such as the line
LAST in the code, but executed FIRST!).

Why? – Because such code will
happen before the asynchronous call delivers any response data.

Doing so is bound to cause confusion when comparing the code with
the output.

运行上面的代码片段显示了我可能不想在异步调用之后编写任何代码(例如代码中最后一行,但首先执行!)。为什么?-因为这样的代码将在异步调用传递任何响应数据之前发生。这样做势必会在将代码与输出进行比较时造成混淆。


3. Promise with .then() – or async/await


The .then() construct was introduced in the ECMA-262 6th Edition
in June 2015
, and the async/await construct was introduced in
the ECMA-262 8th Edition in June 2017.

The code below is still plain JavaScript, replacing the old-school
XMLHttpRequest with Fetch.
4

.Then()构造于2015年6月在ECMA-262第6版中引入,异步/等待构造于2017年6月在ECMA-262第8版中引入。下面的代码仍然是纯JavaScript,用FETCH替换了老式的XMLHttpRequest。4.




fetch('http://api.icndb.com/jokes/random')
.then(response => response.json())
.then(responseBody => {
console.log('.then() - the response body:');
console.log(JSON.stringify(responseBody) + '\n\n');
});

async function receiveAndAwaitPromise () {
const responseBody =
(await fetch('http://api.icndb.com/jokes/random')).json();
console.log('async/await:');
console.log(JSON.stringify(await responseBody) + '\n\n');
}

receiveAndAwaitPromise();

.as-console-wrapper { max-height: 100% !important; top: 0; }




A word of warning is warranted if you decide to go with the
async/await construct.
Note in the above snippet how await is needed in two places.
If forgotten in the first place, there will be no output.
If forgotten in the second place, the only output will be the empty
object, {} (or [object Object] or [object Promise]).

Forgetting the async prefix of the function is maybe the worst of
all – the output will be "SyntaxError: missing ) in parenthetical"
– no mentioning of the missing async keyword.

如果您决定使用Async/AWait构造,则需要警告一句。请注意,在上面的代码片段中,有两个地方需要等待。如果一开始就忘记了,就不会有输出。如果在第二个位置忘记,则唯一的输出将是空对象,{}(或[对象对象]或[对象承诺])。忘记函数的异步前缀可能是最糟糕的--输出将是“语法错误:缺失)在括号中”--没有提到缺失的异步关键字。


4. Promise.all – array of URLs 5


Suppose we need to request a bunch of URLs.
I could send one request, wait till it responds, then send the next
request, wait till it responds, and so on ...

Aargh! – That could take a loong time. Wouldn't it be better if I
could send them all at once, and then wait no longer than it takes
for the slowest response to arrive?

假设我们需要请求一组URL。我可以发送一个请求,等待它响应,然后发送下一个请求,等待它响应,以此类推。啊!-那可能要花很长时间。如果我可以一次把它们全部发送出去,然后等待的时间不超过最慢的响应到达的时间,那不是更好吗?


As a simplified example, I will use:

作为一个简化的例子,我将使用:


urls = ['https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3']

The JSONs of the two URLs:

两个URL的JSON:


{"userId":1,"id":2,"title":"quis ut nam facilis et officia qui",
"completed":false}
{"userId":1,"id":3,"title":"fugiat veniam minus","completed":false}

The goal is to get an array of objects, where each object contains the
title value from the corresponding URL.

目标是获得一个对象数组,其中每个对象都包含来自相应URL的标题值。


To make it a little more interesting, I will assume that there is
already an array of names that I want the array of URL results
(the titles) to be merged with:

为了让它更有趣,我将假设已经有一个名称数组,我希望URL结果数组(标题)与其合并:


namesonly = ['two', 'three']

The desired output is a mashup combining namesonly and urls into an
array of objects:

所需的输出是将仅名称和URL组合到一个对象数组中的混搭:


[{"name":"two","loremipsum":"quis ut nam facilis et officia qui"},
{"name":"three","loremipsum":"fugiat veniam minus"}]

where I have changed the name of title to loremipsum.

在那里我已将标题名称更改为loemipsum。




const namesonly = ['two','three'];

const urls = ['https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3'];

Promise.all(urls.map(url => fetch(url)
.then(response => response.json())
.then(responseBody => responseBody.title)))
.then(titles => {
const names = namesonly.map(value => ({ name: value }));
console.log('names: ' + JSON.stringify(names));
const latins = titles.map(value => ({ loremipsum: value }));
console.log('latins:\n' + JSON.stringify(latins));
const result =
names.map((item, i) => Object.assign({}, item, latins[i]));
console.log('result:\n' + JSON.stringify(result));
});

.as-console-wrapper { max-height: 100% !important; top: 0; }




All the above examples are short and succinctly convey how
asynchronous calls may be used on toyish APIs.

上面的所有示例都很简短,简明扼要地传达了如何在花里胡哨的API上使用异步调用。


References






1
Expressed by the asker of the question as:
they all return undefined.


2
If you think asynchronous calls are confusing, consider having a
look at some questions and answers about asynchronous calls
to see if that helps.


3
The name XMLHttpRequest is as misleading as the X in AJAX
these days the data format of Web APIs is ubiquitously JSON, not XML.


4
Fetch returns a Promise.
I was surprised to learn that neither XMLHttpRequest nor Fetch are
part of the ECMAScript standard.
The reason JavaScript can access them here is because the web browser
provides them.
The Fetch Standard and the XMLHttpRequest Standard
are both upheld by
the Web Hypertext Application Technology Working Group that
was formed in June 2004.


5
This section borrows a lot from
How can I fetch an array of URLs with Promise.all?.




We find ourselves in a universe which appears to progress along a dimension we call "time". We don't really understand what time is, but we have developed abstractions and vocabulary that let us reason and talk about it: "past", "present", "future", "before", "after".

我们发现自己置身于一个似乎沿着我们称之为“时间”的维度前进的宇宙中。我们并不真正理解时间是什么,但我们已经发展出抽象概念和词汇,让我们能够推理和谈论时间:“过去”、“现在”、“未来”、“之前”、“之后”。


The computer systems we build--more and more--have time as an important dimension. Certain things are set up to happen in the future. Then other things need to happen after those first things eventually occur. This is the basic notion called "asynchronicity". In our increasingly networked world, the most common case of asynchronicity is waiting for some remote system to respond to some request.

我们建造的计算机系统--越来越多--把时间作为一个重要的维度。某些事情是为未来发生的而设置的。然后,在最初的事情最终发生之后,还需要发生其他事情。这就是被称为“异步性”的基本概念。在我们日益网络化的世界中,最常见的异步情况是等待某个远程系统响应某个请求。


Consider an example. You call the milkman and order some milk. When it comes, you want to put it in your coffee. You can't put the milk in your coffee right now, because it is not here yet. You have to wait for it to come before putting it in your coffee. In other words, the following won't work:

考虑一个例子。你打电话给送奶人,点了一些牛奶。当它来的时候,你想把它放进你的咖啡里。你现在不能把牛奶放进咖啡里,因为它还没有到。你必须等待它的到来,然后再把它放进你的咖啡里。换句话说,以下方法将不起作用:


var milk = order_milk();
put_in_coffee(milk);

Because JavaScript has no way to know that it needs to wait for order_milk to finish before it executes put_in_coffee. In other words, it does not know that order_milk is asynchronous--is something that is not going to result in milk until some future time. JavaScript, and other declarative languages execute one statement after another without waiting.

因为JavaScript无法知道它需要等待Order_Milk完成后才会执行Put_In_Cafee。换句话说,它不知道ORDER_Milk是异步的--直到将来的某个时候才会产生Milk。和其他声明性语言不需要等待就可以执行一条又一条语句。


The classic JavaScript approach to this problem, taking advantage of the fact that JavaScript supports functions as first-class objects which can be passed around, is to pass a function as a parameter to the asynchronous request, which it will then invoke when it has completed its task sometime in the future. That is the "callback" approach. It looks like this:

解决这个问题的经典方法是将函数作为可以传递的第一类对象来支持,利用这一点,将函数作为参数传递给异步请求,然后在将来某个时候完成任务时调用该请求。这就是“回调”方法。它看起来是这样的:


order_milk(put_in_coffee);

order_milk kicks off, orders the milk, then, when and only when it arrives, it invokes put_in_coffee.

Order_Milk开始,订购牛奶,然后,只有当牛奶到达时,它才调用Put_In咖啡。


The problem with this callback approach is that it pollutes the normal semantics of a function reporting its result with return; instead, functions must not reports their results by calling a callback given as a parameter. Also, this approach can rapidly become unwieldy when dealing with longer sequences of events. For example, let's say that I want to wait for the milk to be put in the coffee, and then and only then perform a third step, namely drinking the coffee. I end up needing to write something like this:

这种回调方法的问题是,它污染了用返回报告其结果的函数的正常语义;相反,函数不能通过调用作为参数给定的回调来报告其结果。此外,在处理较长的事件序列时,此方法可能会很快变得笨拙。例如,假设我想要等待牛奶被放入咖啡,然后并且仅在那时执行第三步,即喝咖啡。最后,我需要写下这样的内容:


order_milk(function(milk) { put_in_coffee(milk, drink_coffee); }

where I am passing to put_in_coffee both the milk to put in it, and also the action (drink_coffee) to execute once the milk has been put in. Such code becomes hard to write, and read, and debug.

在这里,我将把要放入牛奶的牛奶和要在牛奶放入咖啡后执行的操作(喝咖啡)都传递给了放入咖啡的人。这样的代码变得难以编写、读取和调试。


In this case, we could rewrite the code in the question as:

在本例中,我们可以将问题中的代码重写为:


var answer;
$.ajax('/foo.json') . done(function(response) {
callback(response.data);
});

function callback(data) {
console.log(data);
}

Enter promises


This was the motivation for the notion of a "promise", which is a particular type of value which represents a future or asynchronous outcome of some sort. It can represent something that already happened, or that is going to happen in the future, or might never happen at all. Promises have a single method, named then, to which you pass an action to be executed when the outcome the promise represents has been realized.

这就是“承诺”概念的动机,“承诺”是一种代表未来或某种不同步结果的特定类型的价值。它可以代表已经发生的事情,或将在未来发生的事情,或可能永远不会发生的事情。承诺只有一个名为Then的方法,当承诺所代表的结果实现时,您可以将要执行的操作传递给该方法。


In the case of our milk and coffee, we design order_milk to return a promise for the milk arriving, then specify put_in_coffee as a then action, as follows:

在牛奶和咖啡的情况下,我们设计Order_Milk以返回牛奶到达时的承诺,然后将PUT_IN_CAFFICE指定为THEN操作,如下所示:


order_milk() . then(put_in_coffee)

One advantage of this is that we can string these together to create sequences of future occurrences ("chaining"):

这样做的一个好处是,我们可以将它们串在一起,以创建未来发生的序列(“链接”):


order_milk() . then(put_in_coffee) . then(drink_coffee)

Let's apply promises to your particular problem. We will wrap our request logic inside a function, which returns a promise:

让我们将承诺应用于您的特定问题。我们将请求逻辑包装在一个函数中,该函数返回一个承诺:


function get_data() {
return $.ajax('/foo.json');
}

Actually, all we've done is added a return to the call to $.ajax. This works because jQuery's $.ajax already returns a kind of promise-like thing. (In practice, without getting into details, we would prefer to wrap this call so as for return a real promise, or use some alternative to $.ajax that does so.) Now, if we want to load the file and wait for it to finish and then do something, we can simply say

实际上,我们所做的只是向对$.ajax的调用添加了一个返回。这之所以有效,是因为jQuery的$.ajax已经返回了一种类似承诺的东西。(在实践中,不涉及细节,我们倾向于包装这个调用,以便返回一个真正的承诺,或者使用一些替代这样做的$.ajax。)现在,如果我们想要加载文件并等待它完成,然后做一些事情,我们可以简单地说


get_data() . then(do_something)

for instance,

例如,


get_data() .
then(function(data) { console.log(data); });

When using promises, we end up passing lots of functions into then, so it's often helpful to use the more compact ES6-style arrow functions:

在使用Promise时,我们最终会将许多函数传递给Then,因此使用更紧凑的ES6风格的箭头函数通常会很有帮助:


get_data() .
then(data => console.log(data));

The async keyword


But there's still something vaguely dissatisfying about having to write code one way if synchronous and a quite different way if asynchronous. For synchronous, we write

但是,对于必须以一种方式编写代码(如果是同步的,而如果是异步的,则是完全不同的),仍然有一些模糊的不满意之处。对于同步,我们写道


a();
b();

but if a is asynchronous, with promises we have to write

但如果a是异步的,我们必须写下承诺


a() . then(b);

Above, we said, "JavaScript has no way to know that it needs to wait for the first call to finish before it executes the second". Wouldn't it be nice if there was some way to tell JavaScript that? It turns out that there is--the await keyword, used inside a special type of function called an "async" function. This feature is part of the upcoming version of ECMAScript (ES), but it is already available in transpilers such as Babel given the right presets. This allows us to simply write

在上面,我们说过,“在执行第二个调用之前,它没有办法知道它需要等待第一个调用完成”。如果有某种方法告诉JavaScript这一点,那不是很好吗?事实证明,有--等待关键字,用在一种称为“异步”函数的特殊类型的函数中。此功能是即将发布的ECMAScript(ES)版本的一部分,但如果预设正确,它已经在转译程序(如Babel)中可用。这使我们能够简单地编写


async function morning_routine() {
var milk = await order_milk();
var coffee = await put_in_coffee(milk);
await drink(coffee);
}

In your case, you would be able to write something like

在您的情况下,您可以编写如下内容


async function foo() {
data = await get_data();
console.log(data);
}


Here are some approaches to work with asynchronous requests:



  1. Browser Promise object

  2. Q - A promise library for JavaScript

  3. A+ Promises.js

  4. jQuery deferred

  5. XMLHttpRequest API

  6. Using callback concept - As implementation in first answer


Example: jQuery deferred implementation to work with multiple requests




var App = App || {};

App = {
getDataFromServer: function(){

var self = this,
deferred = $.Deferred(),
requests = [];

requests.push($.getJSON('request/ajax/url/1'));
requests.push($.getJSON('request/ajax/url/2'));

$.when.apply(jQuery, requests).done(function(xhrResponse) {
return deferred.resolve(xhrResponse.result);
});
return deferred;
},

init: function(){

this.getDataFromServer().done(_.bind(function(resp1, resp2) {

// Do the operations which you wanted to do when you
// get a response from Ajax, for example, log response.
}, this));
}
};
App.init();





Short answer: Your foo() method returns immediately, while the $ajax() call executes asynchronously after the function returns. The problem is then how or where to store the results retrieved by the async call once it returns.

简而言之:foo()方法立即返回,而$ajax()调用在函数返回后异步执行。然后问题是,一旦异步调用返回,如何或在哪里存储该异步调用检索到的结果。



Several solutions have been given in this thread. Perhaps the easiest way is to pass an object to the foo() method, and to store the results in a member of that object after the async call completes.

在这个帖子里给出了几个解决方案。也许最简单的方法是将一个对象传递给foo()方法,并在异步调用完成后将结果存储在该对象的成员中。



function foo(result) {
$.ajax({
url: '...',
success: function(response) {
result.response = response; // Store the async result
}
});
}

var result = { response: null }; // Object to hold the async result
foo(result); // Returns before the async completes


Note that the call to foo() will still return nothing useful. However, the result of the async call will now be stored in result.response.

请注意,对foo()的调用仍然不会返回任何有用的内容。但是,异步调用的结果现在将存储在Result.Response中。



Use a callback() function inside the foo() success.
Try it in this way. It is simple and easy to understand.

在foo()成功中使用回调()函数。这样试一试。它简单易懂。


var lat = "";
var lon = "";

function callback(data) {
lat = data.lat;
lon = data.lon;
}

function getLoc() {
var url = "http://ip-api.com/json"
$.getJSON(url, function(data) {
callback(data);
});
}

getLoc();


Using Promise


The most perfect answer to this question is using Promise.

对这个问题最完美的回答是使用承诺。


function ajax(method, url, params) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(this.responseText);
};
xhr.onerror = reject;
xhr.open(method, url);
xhr.send(params);
});
}

Usage


ajax("GET", "/test", "acrive=1").then(function(result) {
// Code depending on result
})
.catch(function() {
// An error occurred
});



But wait...!


There is a problem with using promises!

使用承诺是有问题的!


Why should we use our own custom Promise?


I was using this solution for a while until I figured out there is an error in old browsers:

我使用这个解决方案有一段时间了,直到我发现旧浏览器中有一个错误:



Uncaught ReferenceError: Promise is not defined



So I decided to implement my own Promise class for ES3 to below JavaScript compilers if it's not defined. Just add this code before your main code and then safely use Promise!

因此,我决定为ES3实现我自己的Promise类,如果它没有定义的话,它将低于JavaScript编译器。只需将此代码添加到您的主代码之前,然后安全地使用Promise!


if(typeof Promise === "undefined"){
function _typeof(obj) { "@babel/helpers - typeof"; return

_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
var Promise = /*#__PURE__*/function () {
"use strict";

function Promise(main) {
_classCallCheck(this, Promise);
this.main = main;
this.mainExecuted = false;
this.resolved = false;
this.rejected = false;
this.promiseChain = [];
this.handleError = function () {};
this.onResolve = this.onResolve.bind(this);
this.onReject = this.onReject.bind(this);
}
_createClass(Promise, [{
key: "then",
value: function then(handleSuccess) {
if (this.resolved) {
if (!this.rejected) {
this.args = handleSuccess(this.args);
}
} else {
this.promiseChain.push(handleSuccess);
this.main(this.onResolve, this.onReject);
this.thenExecuted = true;
}
return this;
}
}, {
key: "catch",
value: function _catch(handleError) {
this.handleError = handleError;
if (!this.mainExecuted) {
this.main(this.onResolve, this.onReject);
this.thenExecuted = true;
}
return this;
}
}, {
key: "onResolve",
value: function onResolve() {
var _this = this;
this.resolved = true;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
this.args = args;
try {
this.promiseChain.forEach(function (nextFunction) {
_this.args = nextFunction.apply(void 0, _toConsumableArray(_this.args));
});
} catch (error) {
this.promiseChain = [];
this.onReject(error);
}
}
}, {
key: "onReject",
value: function onReject(error) {
this.rejected = true;
this.handleError(error);
}
}]);
return Promise;
}();
}


Of course there are many approaches like synchronous request, promise, but from my experience I think you should use the callback approach. It's natural to asynchronous behavior of JavaScript.

当然,同步请求、承诺等方法有很多,但根据我的经验,我认为应该使用回调方法。这是自然而然的非同步行为的JavaScript。


So, your code snippet can be rewritten to be a little different:

因此,您的代码片段可以重写为稍有不同:


function foo() {
var result;

$.ajax({
url: '...',
success: function(response) {
myCallback(response);
}
});

return result;
}

function myCallback(response) {
// Does something.
}


The question was:

问题是:



How do I return the response from an asynchronous call?



which can be interpreted as:

这可以解释为:



How to make asynchronous code look synchronous?



The solution will be to avoid callbacks, and use a combination of Promises and async/await.

解决方案将是避免回调,并结合使用承诺和异步/等待。


I would like to give an example for an Ajax request.

我想给出一个AJAX请求的例子。


(Although it can be written in JavaScript, I prefer to write it in Python, and compile it to JavaScript using Transcrypt. It will be clear enough.)

(虽然它可以用JavaScript编写,但我更喜欢用Python语言编写,然后使用代码转换将其编译成JavaScript。这将是足够清楚的。)


Let’s first enable jQuery usage, to have $ available as S:

让我们首先启用jQuery使用,以使$可用为S:


__pragma__ ('alias', 'S', '$')

Define a function which returns a Promise, in this case an Ajax call:

定义一个返回承诺的函数,在本例中是一个AJAX调用:


def read(url: str):
deferred = S.Deferred()
S.ajax({'type': "POST", 'url': url, 'data': { },
'success': lambda d: deferred.resolve(d),
'error': lambda e: deferred.reject(e)
})
return deferred.promise()

Use the asynchronous code as if it were synchronous:

使用异步代码,就好像它是同步的:


async def readALot():
try:
result1 = await read("url_1")
result2 = await read("url_2")
except Exception:
console.warn("Reading a lot failed")


Using ES2017 you should have this as the function declaration.

使用ES2017时,您应该将其作为函数声明。


async function foo() {
var response = await $.ajax({url: '...'})
return response;
}

And executing it like this.

并像这样执行它。


(async function() {
try {
var result = await foo()
console.log(result)
} catch (e) {}
})()

Or the Promise syntax.

或者Promise语法。


foo().then(response => {
console.log(response)

}).catch(error => {
console.log(error)

})

Stack Snippet that demonstrates the code above.

演示上述代码的堆栈代码段。




// The function declaration:
async function foo() {
var response = await $.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/1'
})
return response;
}

// Execute it like this:
(async function() {
try {
var result = await foo()
console.log(result)
} catch (e) {}
})()

// Or use Promise syntax:
foo().then(response => {
console.log(response)
}).catch(error => {
console.log(error)
})

.as-console-wrapper { max-height: 100% !important; top: 0; }

<script src=
"https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>




更多回答

@Pommy: If you want to use jQuery, you have to include it. Please refer to docs.jquery.com/Tutorials:Getting_Started_with_jQuery.

@Pommy:如果你想使用jQuery,你必须包括它。请参考docs.jquery.com/Tutorials:Getting_Started_with_jQuery.

In Solution 1, sub jQuery, I could not understand this line: If you use any other jQuery AJAX method, such as $.get, $.getJSON, etc., you have them to $.ajax. (Yes, I realize my nick is a tad ironic in this case)

在解决方案1的subjQuery中,我无法理解这一行:如果您使用任何其他jQuery AJAX方法,如$.get、$.getJSON等,则需要将它们设置为$.ajax。(是的,我意识到我的尼克在这种情况下有点讽刺)

@gibberish: Mmmh, I don't know how it can be made clearer. Do you see how foo is called and a function is passed to it (foo(function(result) {....});)? result is used inside this function and is the response of the Ajax request. To refer to this function, the first parameter of foo is called callback and assigned to success instead of an anonymous function. So, $.ajax will call callback when the request was successful. I tried to explain it a bit more.

@胡言乱语:嗯,我不知道怎么才能说得更清楚。您是否看到了如何调用foo并将函数传递给它(foo(Function(Result){...});)?RESULT在该函数中使用,是对AJAX请求的响应。为了引用该函数,foo的第一个参数被调用回调并被赋值给Success,而不是匿名函数。因此,当请求成功时,$.ajax将回调。我试着解释得更多一点。

The Chat for this question is dead so I'm not sure where to propose outlined changes, but I propose: 1) Change the synchronous part to a simple discussion of why it's bad with no code example of how to do it. 2) Remove/merge the callback examples to only show the more flexible Deferred approach, which I think may also be a little easier to follow for those learning Javascript.

这个问题的讨论结束了,所以我不确定在哪里提出概述的更改,但我建议:1)将同步部分更改为简单的讨论为什么它不好,没有如何做到这一点的代码示例。2)删除/合并回调示例,只展示更灵活的延迟方法,我认为对于学习Java脚本的人来说,这种方法也更容易理解。

@Jessi: I think you misunderstood that part of the answer. You cannot use $.getJSON if you want the Ajax request to be synchronous. However, you should not event want the request to be synchronous, so that doesn't apply. You should be using callbacks or promises to handle the response, as it is explained earlier in the answer.

@Jessi:我认为你误解了答案的这一部分。如果希望AJAX请求是同步的,则不能使用$.getJSON。但是,您不应该让事件希望请求是同步的,因此这不适用。您应该使用回调或承诺来处理响应,正如前面在答案中所解释的那样。

"synchronous requests block the execution of code and can leak memory and events" how can a synchronous request leak memory?

“同步请求会阻塞代码的执行,并可能泄漏内存和事件”,同步请求如何泄漏内存?

While this answer is nice (And we all love XHR2 and posting file data and multipart data is totally awesome) - this shows syntactic sugar for posting XHR with JavaScript - you might want to put this in a blog post (I'd like it) or even in a library (not sure about the name x, ajax or xhr might be nicer :)). I don't see how it addresses returning the response from an AJAX call. (someone could still do var res = x("url") and not understand why it doesn't work ;)). On a side note - it would be cool if you returned c from the method so users can hook on error etc.

虽然这个答案很好(我们都喜欢XHR2,并且发布文件数据和多部分数据非常棒)--这显示了用JavaScript发布XHR的语法甜头--但您可能想把它放到博客文章中(我喜欢),甚至放到库中(不确定名字是x,AJAX或xhr可能更好:)。我看不出它如何解决从AJAX调用返回响应的问题。(有些人仍然可以执行var res=x(“url”)而不理解为什么它不起作用;))。顺便说一句--如果你从方法中返回c,那将会很酷,这样用户就可以挂上错误等等。

2.ajax is meant to be async.. so NO var res=x('url').. That's the entire point of this question and answers :)

2.AJAX应该是异步的。所以没有var res=x(‘url’)..这就是这个问题和答案的全部意义:)

@cocco So you wrote misleading, unreadable code in a SO answer in order to save a few keystrokes? Please don't do that.

@Cocco所以你在so答案中编写了误导性的、不可读的代码,以节省几次击键?请不要那样做。

In short, async functions can either: 1) assign meaningless 'pending' promises or 'undefined' variables to synchronous flow (common gotchas) 2) extract the response body from the fulfilled promise for their own or callback processing 3) return the promise up the 'chain' to another calling async function

简而言之,异步函数可以:1)为同步流(常见的陷阱)赋值无意义的‘待定’承诺或‘未定义’变量2)为它们自己的或回调处理从兑现的承诺中提取响应体3)将承诺沿‘链’向上返回到另一个调用的异步函数

This answer is completely semantic... your success method is just a callback within a callback. You could just have success: handleData and it would work.

这个答案完全是语义的.您的成功方法只是回调中的一个回调。您可能只需要成功:handleData,它就会起作用。

A picture is worth a thousand words, Person A - Ask's person B details to fix his car, in turn Person B - Makes Ajax Call and waits for response from server for car fixing details, when response is received, Ajax Success function calls the Person B function and passes the response as argument to it, Person A receives the answer.

一张图片胜过千言万语,人A-向人B询问修车细节,人B-进行AJAX调用并等待服务器响应修车细节,当收到响应时,AJAX成功函数调用人B函数并将响应作为参数传递给它,人A收到答案。

Would be great if you added lines of code with each image to illustrate the concepts.

如果您在每个图像中添加几行代码来说明概念,那就太好了。

Meanwhile, the guy with the car is stuck on the side of the road. He requires the car is fixed before continuing. He is now alone on the side of the road waiting... He would rather be on the phone waiting for status changes but the mechanic would not do it... The mechanic said he has to get on with his job and can't simply hang out on the phone. Mechanic promised he would call him back as soon as he could. After about 4 hours, the guy gives up and calls Uber. - Example of timeout.

与此同时,开车的人被困在路边。他要求在继续之前先把车修好。他现在独自一人在路边等着……他宁愿在电话上等待状态的改变,但机械师不愿意这样做。这位机械师说,他必须继续工作,不能简单地在电话上闲逛。机械师答应他会尽快给他回电话。大约4个小时后,这名男子放弃了,并给优步打了电话。-超时示例。

But with callback functions, I feel like the person on the left in the last frame is being forced not to give the other person their phone number. Instead they have to tell the other person, "Here's everything I want to do with the information from the dude on the phone. Do all that stuff and never tell me." What am I missing?

但有了回拨功能,我感觉最后一帧左边的人被迫不给另一个人他们的电话号码。取而代之的是,他们必须告诉另一个人,“这是我想要做的所有事情,从电话里的那个家伙那里得到的信息。做所有的事情,永远不要告诉我。”我遗漏了什么?

@FingLixon It's not a perfect comic by any stretch :-D. The 2nd image should illustrate what happens when you try to read a value too early (before a callback has occurred). The 3rd image illustrates setting up a callback method: The guy on the left basically IS the callback handler: He will be called with the information once it's available and can then do with it whatever he wants. I now think it was a bad idea to have TWO phone calls in this comic: The call to the shop and the call to the guy on the left. I should have simplified that, sorry about that.

@FingLixon这绝对不是一本完美的漫画:-D。第二个图像应该说明当您尝试过早地(在回调发生之前)读取值时会发生什么。第三幅图演示了设置回调方法:左边的人基本上是回调处理程序:一旦信息可用,他将被调用,然后可以随心所欲地处理它。我现在认为在这本漫画里有两个电话是个坏主意:给商店的电话和给左边那个人的电话。我应该简化一下的,很抱歉。

I don't know who voted it negative. But this is a work around which has worked in fact i used this approach to create a whole application. The jquery.ajax don't return data so its better to use the above approach. If it's wrong then please explain and suggest better way to do it.

我不知道谁投了反对票。但这是一个已经奏效的工作,事实上我使用这种方法创建了整个应用程序。Jquery.ajax不返回数据,所以最好使用上面的方法。如果这是错误的,请解释并建议更好的方法。

Sorry, I forgot to leave a comment (I usually do!). I downvoted it. Downvotes don't indicate factual correctness or lack of, they indicate usefulness in the context or lack of. I don't find your answer useful given Felix's which already explains this only in much more detail. On a side note, why would you stringify the response if it's JSON?

对不起,我忘了留言(我通常都会这样做的!)我否决了它。向下投票并不表示事实的正确性或缺乏,它们表示在上下文中有用处或缺乏。我不认为你的答案有用,因为费利克斯已经更详细地解释了这一点。顺便说一句,如果响应是JSON,您为什么要将其串化?

ok.. @Benjamin i used stringify, to convert a JSON Object to string. And thanks for clarifying your point. Will keep in mind to post more elaborate answers.

好的.。@Benjamin我使用了stringify,将JSON对象转换为字符串。谢谢你澄清了你的观点。将牢记发布更详细的答案。

This does not explain how promises would solve this issue at all though.

然而,这根本解释不了承诺将如何解决这个问题。

jQuery and fetch methods both return promises as well. I would suggest revising your answer. Though jQuery's isn't quite the same (then is there, but catch isn't).

JQuery和Fetch方法也都返回承诺。我建议修改你的回答。尽管jQuery的不完全相同(Then是存在的,但Catch不是)。

Could you explain how the if (--expecting === 0) part of the code works please? The callback version of your solution is working great for me, I just don't understand how, with that statement, you are checking the number of responses completed. Appreciate it's just lack of knowledge on my part. Is there an alternative way that check could be written?

你能解释一下代码中的if(--expearding=0)部分是如何工作的吗?您的解决方案的回调版本对我来说工作得很好,我只是不明白如何使用该语句检查完成的响应数量。我很感激,只是我对此缺乏了解。有没有其他方式可以写支票?

@Sarah: expecting starts out with the value of array.length, which is how many requests we're going to make. We know the callback won't be called until all of those requests are started. In the callback, if (--expecting === 0) does this: 1. Decrements expecting (we've received a response, so we're expecting one fewer response) and if the value after the decrement is 0 (we're not expecting any more responses), we're done!

@Sarah:期望从array.long的值开始,这就是我们要发出的请求数量。我们知道在启动所有这些请求之前不会调用回调。在回调中,如果(--defining=0)执行以下操作:1.递减预期(我们已收到响应,因此我们期望减少一个响应),并且如果递减后的值为0(我们不再期待更多的响应),我们就完成了!

@Henke - I think it is indeed personal preference, and while normally I'd prefer to log raw data and let the console handle it, in this specific case I think you're right about the change. Thanks! :-)

@Henke-我认为这确实是个人喜好,虽然通常我更喜欢记录原始数据并让控制台处理它,但在这种特定的情况下,我认为您关于更改的看法是正确的。谢谢!:-)

Out of convenience for myself (and others?), adding a link to a related answer: How to make many asynchronous calls and wait for them all.

出于对我自己(和其他人?)的方便,我添加了一个指向相关答案的链接:如何进行多个异步调用并等待它们。

This is fine at global scope, but in some module context you probably want to ensure right context for the callback e.g. $.ajax({url: "api/data", success: fooDone.bind(this)});

这在全局范围内很好,但在某些模块上下文中,您可能希望确保回调的上下文正确,例如$.ajax({url:“api/data”,uccess:fooDone.ind(This)});

This is actually incorrect as React is one-way data binding

这实际上是不正确的,因为Reaction是单向数据绑定

@MatthewBrent you are not wrong, but not right also, React props are object and if changed, they change throughout the application, but its not a way that React developer recommend to use it...

@MatthewBrent你没有错,但也不是对的,Reaction道具是对象,如果改变,它们在整个应用程序中都会改变,但这不是Reaction开发人员推荐使用它的一种方式……

is this still considered the best way to return a value from a promise or async/await?

这仍然被认为是从承诺或异步/等待中返回值的最佳方式吗?

@edwardsmarkf Personally I don't think there's a best way as such. I use promises with then/catch , async/await as well as generators for async portions of my code. It largely depends on the context of usage.

@edwardsmarkf我个人认为没有最好的方法。我将承诺与Then/Catch、Aync/AWait以及我的代码的异步部分的生成器一起使用。这在很大程度上取决于使用的上下文。

There is nothing special about using an object here. It would work as well if you assigned he response directly to result. It works because you are reading the variable after the async function is complete.

在这里使用对象并没有什么特别之处。如果您将响应直接分配给结果,也会同样有效。它之所以有效,是因为您在异步函数完成后读取变量。

is this similar to generator functions? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…*

这类似于生成函数吗?Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…*

Is this still relevant?

这一点还相关吗?

You can make use of async-await if you're using some of the newest versions of node. If someone is stuck with older versions they can use this method.

如果您使用的是NODE的一些最新版本,则可以使用Async-AWait。如果有人坚持使用较旧的版本,他们可以使用此方法。

Unfortunately, this works only with functions that return promises – for example it doesn't work with Node.js API, which uses callbacks. And I wouldn't recommend using it without Babel, because not everyone uses "current browsers".

遗憾的是,这只适用于返回承诺的函数--例如,它不适用于使用回调的Node.js API。我不推荐在没有Babel的情况下使用它,因为并不是每个人都在使用“当前的浏览器”。

@MichałPerłakowski node 8 includes nodejs.org/api/util.html#util_util_promisify_original which can be used to make the node.js API return promises. Whether you have the time and money to support non-current browsers obviously depends on your situation.

@Micha API Per nodejs.org/api/util.html#util_util_promisify_original Akowski节点8包含nodejs.org/api/util.html#util_util_promisify_original,可用于做出łł返回承诺。你是否有时间和金钱来支持非当前浏览器,显然取决于你的情况。

IE 11 is still a current browser in 2018, sadly and it doesn't support await/async

IE 11在2018年仍然是当前的浏览器,遗憾的是,它不支持等待/异步

IE11 is not a current browser. It was released 5 years ago, has a worldwide market share of 2.5% according to caniuse, and unless someone is doubling your budget to ignore all current tech then it's not worth most people's time.

IE11不是当前的浏览器。它是5年前发布的,根据Caniuse的数据,它在全球的市场份额为2.5%,除非有人加倍你的预算,忽略所有当前的技术,否则它不值得大多数人花时间。

This is interesting. I like how it allows to code async calls the way you'd do it in other languages. But technically it's not real JavaScript?

这很有趣。我喜欢它允许编写异步调用的方式,就像用其他语言编写代码一样。但从技术上讲,它不是真正的JavaScript?

Do you consider generators / async generators to be an async API solution alone ? Or you would use generators to wrap another asynchronous API like promise/deffered ? I agree it is another strong addition to the async universe but still haven't found the right usage of generators that would make me adopt them.

您是否认为生成器/异步生成器是一个单独的异步API解决方案?或者,您会使用生成器来包装另一个异步API,如Promise/Deffed?我同意这是对异步世界的又一个强有力的补充,但仍然没有找到让我采用它们的生成器的正确用法。

Why include a Stack Snippet that outputs an error?

为什么要包含输出错误的Stack代码段?

While this works, it's not really better than assigning to a global variable.

虽然这种方法有效,但并不比赋值给全局变量更好。

I reckon you could also use a callback :D, but this is incredible.

我想你也可以使用回调:D,但这太不可思议了。

core-js existed in 2018. No reason to invent your own promise. Looks cool anyways.

CORE-JS于2018年存在。没有理由编造你自己的承诺。反正看起来很酷。

There's nothing inherently asynchronous about callbacks or JavaScript.

回调或Java脚本本身没有任何异步性。

Why keep var result; and return result;? The latter will still always return undefined!

为什么要保留变量结果;并返回结果;?后者仍将始终返回UNDEFINED!

Anyone interested in using async / await will likely also want to read this answer (and possibly my comment below it :-).

任何对使用Async/AWait感兴趣的人可能也想阅读这个答案(可能还有我下面的评论:-)。

could that second function to reuseable??

第二个功能可以重复使用吗?

How do you use the results if oncolse,log is called? Doesn't everything just go to the console at that point?

如果调用oncolse,log,您将如何使用结果?在这一点上,不是所有的东西都直接进入控制台了吗?

This is a fine and helpful answer that clearly demonstrates how to correctly use the async - await duality feature. One thing to note is that async and await are actually not needed in the function foo(). (Remove them both and the code still runs just fine.) This is because foo() returns a Promise, and as long as the code receiving the Promise awaits it, everything will be fine. ~ * ~ * ~ * ~ Note: the async - await feature was introduced in the ECMA-262 8th Edition in June 2017.

这是一个很好的、有帮助的答案,它清楚地演示了如何正确使用异步等待二元性特性。需要注意的一点是,函数foo()中实际上并不需要异步和等待。(将它们都删除,代码仍然可以正常运行。)这是因为foo()返回一个承诺,只要接收承诺的代码等待它,一切都会好起来的。~*~*~*~注意:2017年6月,ECMA-262第8版引入了异步等待功能。

I have a requirement to return some data after calculation from the callback function. How could i do that

我需要从回调函数返回一些计算后的数据。我怎么能那样做呢?

It's not possible.

这不可能。

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com