Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
309 views
in Technique[技术] by (71.8m points)

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

I have a function foo which makes an Ajax request. (我有一个函数foo ,它发出Ajax请求。) How can I return the response from foo ? (如何返回foo的响应?)

I tried returning the value from the success callback as well as assigning the response to a local variable inside the function and returning that one, but none of those ways actually return the response. (我尝试从success回调中返回值,以及将响应分配给函数内部的局部变量并返回该局部变量,但这些方法均未真正返回响应。)

function foo() {
    var result;

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

    return result;
}

var result = foo(); // It always ends up being `undefined`.
  ask by Felix Kling translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

→ For a more general explanation of async behaviour with different examples, please 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 . (Ajax中A代表异步 。) 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; (在您的示例中, $.ajax立即返回,下$.ajax语句return result;) , is executed before the function you passed as success callback was even called. (会在您调用success回调函数之前执行。)

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(); (即使findItem可能要花很长时间才能执行,但var item = findItem();之后的任何代码都将执行) has to wait until the function returns the result. (必须等到函数返回结果。)

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

Instead of waiting for the response, the execution continues immediately and the statement after the Ajax call is executed. (无需等待响应,而是立即继续执行,并执行Ajax调用后的语句。) 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. (在调用之后执行的所有语句都将在调用回调之前执行。)


Solution(s) (解决方案)

Embrace the asynchronous nature of JavaScript! (拥抱JavaScript的异步特性!) While certain asynchronous operations provide synchronous counterparts (so does "Ajax"), it's generally discouraged to use them, especially in a browser context. (尽管某些异步操作提供了同步对应项(“ 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. (JavaScript在浏览器的UI线程中运行,任何长时间运行的进程都将锁定UI,从而使其无响应。) 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的执行时间有上限,浏览器会询问用户是否继续执行。)

All of this is 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) (带有async/await承诺 (ES2017 +,如果使用转译器或再生器,则在较旧的浏览器中可用))
  • Callbacks (popular in node) (回调 (在节点中受欢迎))
  • Promises with then() (ES2015+, available in older browsers if you use one of the many promise libraries) (then()承诺 (ES2015 +,如果您使用许多promise库之一,则在较旧的浏览器中可用))

All three are available in current browsers, and node 7+. (在当前浏览器和节点7+中,所有这三个功能均可用。)


ES2017+: Promises with async/await (ES2017 +:带有async/await承诺)

The ECMAScript version released in 2017 introduced syntax-level support for asynchronous functions. (2017年发布的ECMAScript版本引入了对异步功能的语法级支持 。) With the help of async and await , you can write asynchronous in a "synchronous style". (借助asyncawait ,您可以以“同步样式”编写异步。) The code is still asynchronous, but it's easier to read/understand. (该代码仍然是异步的,但更易于阅读/理解。)

async/await builds on top of promises: an async function always returns a promise. (async/await建立在promise之上: async函数总是返回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. (await “解开”承诺,并导致承诺被解决的值,或者如果承诺被拒绝,则抛出错误。)

Important: You can only use await inside an async function. (重要提示:您只能在async函数内使用await 。) Right now, top-level await isn't yet supported, so you might have to make an async IIFE ( Immediately Invoked Function Expression ) to start an async context. (目前,尚不支持顶层await ,因此您可能必须进行异步IIFE( 立即调用函数表达式 )才能启动async上下文。)

You can read more about async and await on MDN. (您可以阅读有关async并在MDN上await更多信息。)

Here is an example that builds on top of delay above: (这是一个基于以上延迟的示例:)

// Using 'superagent' which will return a promise.
var superagent = require('superagent')

// This is isn't declared as `async` because it already returns a promise
function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}


async function getAllBooks() {
  try {
    // GET a list of book IDs of the current user
    var bookIDs = await superagent.get('/user/books');
    // wait for 3 seconds (just for the sake of this example)
    await delay();
    // GET information about each book
    return await 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 . (当前的浏览器和<a href


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...