我正在主线程中进行同步REST API调用。jQuery(或浏览器?)抱怨。但是我不知道如何异步编码它,或者至少在读取时,代码不那么令人困惑。
这是我正在做的事情的简化版本:
<html>
<head>
<script type="text/javascript" src="/js/jquery.min.js" ></script>
</head>
<body>
<script type="text/javascript">
function get_foobar(val1, val2){
$.ajax({
url: 'http://localhost:8000/api/' + va1 + '/' + val2,
success: function (data) {
let my_object = $.parseJSON(data)
//console.log(data);
console.log(my_object);
let params = my_object['params'];
let blob = my_object['the_thing'];
var foobar = new FooBar(var1, var2, params, blob);
return foobar; // <- object created here ...
},
async: false
});
}
$(document.ready(function(){
foobar = get_foobar($('#field1').val, $('#field2').val());
console.log(foobar); // <- undefined here ... wtf?
});
</script>
</body>
</html>
为什么函数不返回创建的foobar
对象?
这里有几个问题。
- 您没有在
get_foobar
中返回任何内容。 - 您无法访问成功回调的返回值。
- 您永远不要使用
async: false
解决此问题的常见方法是使用Promises
function get_foobar(val1, val2) {
return new Promise(function(resolve, reject) {
$.ajax({
url: 'http://localhost:8000/api/' + va1 + '/' + val2,
success: function (data) {
let my_object = $.parseJSON(data)
//console.log(data);
console.log(my_object);
let params = my_object['params'];
let blob = my_object['the_thing'];
var foobar = new FooBar(var1, var2, params, blob);
resolve(foobar); // <- resolve the object created here ...
},
error: function(err) {
reject(err); // REJECT any errors that occur in request
}
});
});
}
get_foobar($('#field1').val, $('#field2').val())
.then(function(foobar) {
console.log(foobar)
})
.catch(function(error) {
console.error('something went wrong!', error);
});
回调上的解决方案:
<html>
<head>
<script type="text/javascript" src="/js/jquery.min.js" ></script>
</head>
<body>
<script type="text/javascript">
function get_foobar(val1, val2, cb){
$.ajax({
url: 'http://localhost:8000/api/' + va1 + '/' + val2,
success: function (data) {
let my_object = $.parseJSON(data)
//console.log(data);
console.log(my_object);
let params = my_object['params'];
let blob = my_object['the_thing'];
var foobar = new FooBar(var1, var2, params, blob);
cb(foobar);
},
//async: false//no reason to use it
});
}
$(document.ready(function(){
get_foobar($('#field1').val, $('#field2').val(), function(foobar){
console.log(foobar);
});
});
</script>
</body>
</html>
以下是一个示例,显示了您面临的问题,以及适当地获取数据的正确方法(不幸的是,同步提出Ajax请求是不好的练习,并且支持它的支持将从浏览器中从浏览器中删除。未来,所以您绝对不应该依靠它)。
主要问题是,到您的异步代码运行时,称为它的功能早就运行并已经返回。在此示例中,您需要一个像timer1
这样的函数来返回结果,但是它将结果返回到setTimeout
的内部代码,实际上是从那里调用的。setTimeout
什么都没有返回(因此undefined
)。您需要做的是使用承诺或简单的情况,回调。下面代码中的第二个示例使用回调在异步操作后运行其他代码。
我建议您阅读此信息:https://developer.mozilla.org/en-us/docs/web/javascript/eventloop。它将帮助您了解JavaScript中的异步代码,以及为什么事情以它们的工作方式工作。
var log = (function(){
var out = document.querySelector('#out');
return function(msg){
out.innerHTML += '<div>' + msg + '</div>';
}
})();
function getSomethingAsyncTheWrongWay(){
setTimeout(function timer1(){
log('Round 1: First in code, last in console');
return 'Result';
}, 1000);
}
log(getSomethingAsyncTheWrongWay());
log('Round 1: Last in code, first in console');
function getSomethingAsyncTheRightWay(callback){
setTimeout(function timer2(){
log('Round 2: First in code, last in console');
callback('Result');
}, 1000);
}
getSomethingAsyncTheRightWay(function(result){
log(result);
});
log('Round 2: Last in code, first in console');
#out{
color:green;
background:#000;
font-family:courier new;
padding:1em;
font-weight:bold;
}
<div id=out></div>
您将无法将'Blobby'直接返回到内存变量。
将" blobby"传递到全局变量。
尝试以下一个:
jQuery-将AJAX响应存储到全局变量
jQuery-将ajax json响应存储为变量