我如何从函数 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`
}
另一种方法是从无同步函数中返回值,是通过将结果从无同步函数中存储的对象。
下面是相同的例子:
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');
});
我正在使用结果对象来存储在无同步操作期间的值,这使得结果即使在无同步工作后也可用。
我使用这个方法很多,我会感兴趣知道这个方法有多好运作,在那里通过连续模块将结果传输回来。
如果您不使用 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开始指南。
这是其中一个地方,在许多新的JavaScript框架中使用的双向数据连接或存储概念将为您工作。
因此,如果您使用 Angular, React 或任何其他框架,使双向数据连接或存储概念,这个问题只是为您固定,所以简单地说,您的结果在第一阶段是不确定的,所以您在收到数据之前得到了结果 = 不确定的,然后一旦您获得结果,它将被更新并被分配到新的值,你的 Ajax 呼叫的反应。
但是,你如何在纯粹的JavaScript或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
});
虽然承诺和呼叫在许多情况下工作顺利,但背部疼痛是表达这样的东西:
if (!name) {
name = async1();
}
async2(name);
您最终会通过 async1; 检查名称是否不定义,并根据此呼叫回复。
async1(name, callback) {
if (name)
callback(name)
else {
doSomething(callback)
}
}
async1(name, async2)
雖然在小例子中很好,但當你有許多類似案例和錯誤處理涉及時,它會變得令人不安。
纤维可以帮助解决这个问题。
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
}
您可以在此处查看项目。