提问人:user3425506 提问时间:7/27/2022 更新时间:7/28/2022 访问量:71
如何让回调异步运行?
How to make callback run asynchronously?
问:
我有一个名为getAandB的JavaScript函数,它接受回调。getAandB 首先使用 ajax 获取值 'a'。然后,它调用值为“a”作为参数的回调。回调获取值“b”,并将 console.logs “a”和“b”都记录到控制台。所以我进入了控制台。{"key":"a"} {"key":"b"}
我以为两个ajax调用会同时/异步发生。然而,它们似乎一个接一个地运行,即。同步。
ajax 请求的 JavaScript 代码和 PHP 代码如下所示:
index.html:
<script>
function getAandB(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
callback(xhr.responseText)
}
}
xhr.send();
}
function callback(resultA){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
const resultB = xhr.responseText;
console.log(resultA, resultB);
}
}
xhr.send();
}
getAandB(callback);
</script>
ajax-a.php:
<?php
sleep(5);
$response = [
"key" => "a",
];
echo json_encode($response);
ajax-b.php 的代码与 ajax-a 相同.php只是 $response.key 的值是 b 而不是 a。
我认为上面的代码会导致同时进行ajax调用以获取“a”和“b”。但是,如果 ajax-a.php 和 ajax-b.php 的 PHP 代码都休眠了 5 秒,则控制台 .log 需要 10 秒才能出现。如果只有一个ajax-?.PHP 脚本休眠 5 秒,然后需要 5 秒才能显示控制台 .log。
如何使用回调来允许我组合ajax调用的结果,就像我在这里所做的那样,但使单个调用同时/异步发生?或者,是否无法通过回调来实现这一点?
答:
如果您希望向我发出对 ajax-b 的请求与对 ajax-a 的请求大致同时发出,那么您需要在大约相同的时间进行相应的调用。xhr.send()
目前,对 ajax-b 的调用是作为其中的一部分进行的,只有在收到对 ajax-a 请求的响应后才能调用。send()
callback()
然后,您需要添加其他逻辑来确定何时收到两个响应,以便同时记录两个数据位(假设您仍然希望这样做)。
一个粗略而现成的方法,保持你目前的方法,看起来像这样:
function getA(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
callback(xhr.responseText)
}
}
xhr.send();
}
function getB(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
const resultB = xhr.responseText;
callback(xhr.responseText)
}
}
xhr.send();
}
function getAandB() {
const data = [];
function callback(responseData) {
data.push(responseData);
if (data.length === 2) {
console.log(...data);
}
}
getA(callback);
getB(callback);
}
getAandB();
不过,这些天我们有更好的工具,这要归功于原生支持它们的承诺和现代 API(如 fetch)。
async function getAandB() {
const dataPromises = [
fetch("./ajax-a.php").then(r => r.text()),
fetch("./ajax-b.php").then(r => r.text())
];
const data = await Promise.all(dataPromises);
console.log(...data);
}
getAandB();
评论
text
fetch
ok
status
我尝试编辑我的问题,但“编辑队列已满”。
我花了一段时间才理解@Quentin的答案,但我终于意识到它依赖于这样一个事实,即回调函数的两个实例化都在更改同一个变量(我认为这是通过引用调用的,并且是数组的默认情况)。鉴于此,尽管实例化彼此一无所知,但可以通过检查数据数组是否更新了两次来了解两个 ajax 调用何时完成。如果有,那么两者都必须已经完成,并且可以安慰数据。
不需要 getAandB 函数。这个更简单、更不容易混淆的代码与 Quentin 的回答完全相同:
<script>
const data = [];
function getA(){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
data.push(xhr.responseText);
if (data.length === 2){
console.log(...data);
}
}
}
xhr.send();
}
function getB(){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
data.push(xhr.responseText);
if (data.length === 2){
console.log(...data);
}
}
}
xhr.send();
}
getA();
getB();
</script>
评论
xhr.onreadystatechange
ajax-b
ajax-a
callback
ajax-a