我如何从函数 foo 返回一个无同步请求的答案/结果?

我正在尝试从呼叫返回的值,以及将结果分配到函数内部的本地变量,并返回其中一个,但没有这些方式实际上返回答案 - 他们都返回不确定的或无论变量结果的初始值是什么。

一个不同步函数的例子,接受召回(使用 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`
}

使用 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`
}

例如,使用那时承诺的区块:

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

当前回答

等待

请求以无同步的方式工作,所以你不能像典型代码那样同步阅读数据。 但是,使用 async/await 你可以创建一个与常见的同步/序列风格相似的无同步代码. 处理响应数据的代码必须由一个无同步函数(在下面的剪辑中加载)并在它里面你需要在 foo()(whic)之前添加等待关键字。

async 函数 foo() { var url = 'https://jsonplaceholder.typicode.com/todos/1'; var result = (await fetch(url)).text(); // 或.json() return result; } async 函数 load() { var result = await foo(); console.log(result); } load();

记住,一个无与伦比的功能总是(显而易见)将其结果转化为一个承诺(因此它返回一个承诺)。

其他回答

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

var item = findItem();

// Do something with item
doSomethingElse();

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



重要: 您只能在一个 async 函数或 JavaScript 模块中使用等待。 顶级等待不支持模块之外,因此您可能需要创建一个 async IIFE (即时邀请函数表达) 以启动一个 async 背景,如果不使用模块。

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


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

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

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

foo(myCallback);

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

function foo(callback) {
    $.ajax({
        // ...
        success: function(response) {
            // For example, filter the response
            callback(filtered_response);
        }
    });
}


更多关于承诺的信息: HTML5 Rocks - JavaScript 承诺。

副注:jQuery的废弃物品

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

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

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
}

但修正很容易:

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

不推荐:同步“Ajax”通话

正如我提到的那样,一些(!)无同步操作有同步对手,我不支持它们的使用,但为了完整性,这里是如何进行同步呼叫:

没有 jQuery

jQuery

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

如果您使用任何其他 jQuery Ajax 方法,如 $.get, $.getJSON 等,您必须将其更改为 $.ajax (因为您只能将配置参数转移到 $.ajax)。

如果您不使用 jQuery 在您的代码中,这个答案是为您

function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // Always ends up being 'undefined'

(注意,对于使用新的Fetch API、Angular 或承诺的人,我在下面添加了另一个答案)


你所面临的

这里有一个简单的模拟:

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

(重定向)

function onComplete(a){ // When the code completes, do this
    alert(a);
}

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

使用将是:

getFive(onComplete);

同步AJAX - 不要这样做!!!

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

二、修复代码

如:

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

变成:

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

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

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

我们现在已经使我们的 foo 函数接受一个行动运行,当 AJAX 成功完成时,我们可以通过检查答案状态是否不为 200 进行进一步扩展,并按照此进行操作(创建一个错误处理器等)。

如果你仍然很难理解这一点,请阅读MDN的AJAX开始指南。

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

这个问题的经典JavaScript方法,利用JavaScript支持作为可以通过的第一类对象的功能,是将一个功能作为一个参数转移到无同步的请求,它将随后引用,当它在未来完成任务时。

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(function(milk) { put_in_coffee(milk, drink_coffee); }

我正在转到把牛奶放进去,以及当牛奶放进去后执行的行动(喝咖啡)。

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

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

加入承诺

order_milk() . then(put_in_coffee)

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

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

get_data() . then(do_something)

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

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

a();
b();

a() . then(b);

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

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

您正在使用 Ajax 错误. 想法不是要有它返回任何东西,而是将数据转移到所谓的召回功能,处理数据。

这就是:

function handleData( responseData ) {

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

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

在提交处理器中返回任何东西不会做任何事情,你必须或者放弃数据,或者直接在成功函数中做你想要的事情。

让我们先看看森林,先看看树木。

这里有很多有很好的详细信息的答案,我不会重复任何一个。在JavaScript中编程的关键是首先有正确的整体执行的心理模式。

您的输入点(s)是作为一个事件的结果执行. 例如,一个脚本标签与代码被加载到浏览器. (因此,这就是为什么你可能需要担心页面的准备运行你的代码,如果它需要DOM元素首先建造,等等) 您的代码执行完成 - 尽管许多无同步的呼叫它做 - 没有执行任何你的呼叫回复

但你不應該使用任何戰術工具來解決一個問題,直到你很舒服的實際問題領域. 圖描這些依賴的地圖,知道什麼需要執行時。