如何使用2个依赖于另一个的XMLHttpRequest?

kis*_*dbn 10 javascript xmlhttprequest

我正在开发一个项目,我有两个XMLHttpRequest()对象,比如A和B.

我想要完成的是当A完成获取数据项列表时,将触发B以根据以前获取的先前数据项获取更多项.

目前我的问题是两个对象彼此独立工作.

我的代码如下:

            var A = new XMLHttpRequest();

            var B = new XMLHttpRequest();

            A.open("GET", directory, true);
            A.onreadystatechange = function () {

                if (A.readyState === 4) {
                    if (A.status === 200 || A.status == 0) {
                     //does... something
                     }
                }

            }
            A.send(null);
            while(true){

                B.open("GET", another_directory, false);
                B.overrideMimeType("application/document");
                B.send(null);
                if (B.status == "404")
                continue;

                 //does... something else
            }
Run Code Online (Sandbox Code Playgroud)

此代码无法正常工作,因为我发现在A完成之前,evertime B会继续进行.我基本上不知道要使用哪个事件.

我怎样才能实现目标?我可以使用哪些事件以便在完成A后立即同步处理B.

小智 15

好的,让我们从你的代码开始吧.我已经添加了一些评论,所以现在您可以了解问题的根源:

var A = new XMLHttpRequest(); //You create an XMLHttpRequest object
var B = new XMLHttpRequest(); //And an another

A.open("GET", directory, true); 

/* Now you open a GET request to DIRECTORY, with async TRUE. The third parameter can 
make a request sync or async, but sync is not recommended as described below. */

A.onreadystatechange = function () {
    if (A.readyState === 4) {
        if (A.status === 200 || A.status == 0) {

        /* So you registered an event listener. It runs when the readyState changes.
        You can use it to detect if the request is finished or not. If the readyState is
        4, then the request is finished, if the status code is 200, then the response is
        OK. Here you can do everythin you want after the request. */

         }
    }

}

A.send(null); //Now you send the request. When it finishes, the event handler will
// do the processing, but the execution won't stop here, it immediately goes to the 
// next function

while(true){ // Infinite loop
     B.open("GET", another_directory, false); //Open request B to ANOTHER_DIRECTORY,
     // but now, request B will be synchronous

     B.overrideMimeType("application/document"); // Configure mime type

     B.send(null); // Send the request

     if (B.status == "404")
         continue;
         // If it's not found, then go to the next iteration

     // and do something else
}
Run Code Online (Sandbox Code Playgroud)

我希望现在你可以看到问题的根源.当您运行此脚本时,您启动异步请求,然后立即启动下一个.现在您可以选择2种方式.

从回调运行下一个请求(推荐)

这是更好的方式.因此,启动您的第一个(异步)请求,并在事件监听器(您进行处理)中,您可以启动下一个请求.我在这里做了一个评论的例子:http://jsfiddle.net/5pt6j1mo/1/

(你可以在没有数组的情况下做到 - 这只是一个例子)

如果使用这种方式,那么在等待响应之前,GUI不会冻结.一切都将负责,以便您可以与页面进行交互,您可以创建取消按钮等.

同步AJAX(不推荐)

我不推荐它,因为Chrome中的"主线程上的同步XMLHttpRequest已被弃用",但如果您真的想要,那么您可以尝试使用此解决方案.所以XMLHttpRequest的open函数有3个参数:

  • 方法:使用哪种HTTP methid
  • URL:要请求的URL
  • ASYNC:异步请求?如果为false,则它将是同步的,这意味着在您调用.send()之后,它将暂停执行,直到响应返回.

因此,如果您将第三个参数设置为FALSE,那么您可以轻松地执行此操作......但您不应该这样做!


Ben*_*aum 10

这是一个替代解决方案,使用fetch APIpromisify native XHR,这个问题变得更加简单:

fetch(directory).then(function(response){
    // some processing
    return fetch(another_directory); // can change content type too, see the mdn docs
}).then(function(responseTwo){
      // all processing is done
}).catch(function(err){
      // handle errors from all the steps above at once
});
Run Code Online (Sandbox Code Playgroud)

这与XHR一样原生,并且使用promises管理要简单得多.


zip*_*zit 4

(经过长时间的编辑)我强烈建议您花时间了解 JavaScript 中异步调用的本质。这是一些推荐阅读的内容。JavaScript 中的异步编程 我认为这很简单,足以理解正在发生的事情。注意:请停止阅读“进入 Mobl”。

在 JavaScript 中,当您调用函数时,系统会将该函数放入“队列”中,并带有隐式指令,以便您尽快运行它。它对每个函数调用都执行此操作。在您的情况下,您告诉系统运行 A,然后运行 ​​B。A 进入队列,B 进入队列。它们作为单独的函数提交。B 碰巧先跑了。

对于普通函数,如果要控制顺序,可以将A函数调用嵌套在B函数调用中。但是哎呀。您正在使用 XMLHttpRequest,因此限制了您自定义功能的能力。请继续阅读。查看有关该主题的 Ajax 模式 查看“异步调用”段落。看看你的代码...

A.onreadystatechange = function () {
    if (A.readyState === 4) {
         if (A.status === 200 || A.status == 0) {
             //does... something
             (RUN ALL THE B.methods right here...)
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为,假设您想要一个无 jQuery 的解决方案,这将带您到达目的地。

对于只想要一个功能正常的系统,并且不想更好地理解该语言的人,这里有一个 jquery 解决方案...请注意 B 函数调用是如何嵌套在 A 函数调用中的。请注意,此嵌套的顺序基于 jQuery success 标签的存在。如果不使用 jQuery,您将必须根据需要手动嵌套函数。

var special_value;
$("button").click(function(){
    $.ajax({url: "demo_testA.html", 
            type: 'GET',
            success: function(resultA){
               special_value = resultA;
               $.ajax({url: "demo_testB.html",
                      type: 'GET', 
                      data: special_value, 
                      success: function(resultB){
                            $("#div1").html(resultB);
               }});
    });
});
Run Code Online (Sandbox Code Playgroud)

我想说的是,使用更好的沟通方式来帮助你自己会更容易。如果你不喜欢某件事,那就说出来。如果您不明白某些内容,请要求更多说明或编辑您的问题陈述。反馈是一件好事。

  • 是的,如果你觉得OP不愿意沟通,就“不回答”然后继续。如果您不想改进您的帖子,您可能需要删除它。 (12认同)
  • 该问题未标记为 jQuery,并且此答案未能给出问题的任何解释或建议的解决方案。 (5认同)