2015-03-14 16 views
10

Tôi đang làm việc trên một dự án mà tôi có 2 đối tượng XMLHttpRequest(), A và B.Làm thế nào để làm việc với 2 XMLHttpRequest phụ thuộc vào cái khác?

Điều tôi muốn thực hiện là khi kết thúc tìm nạp danh sách các mục dữ liệu, B sẽ được kích hoạt để tìm nạp các mục khác dựa trên các mục dữ liệu trước được tìm nạp theo A.

Hiện tại, vấn đề của tôi là hai đối tượng đang hoạt động độc lập với nhau.

Mã của tôi là dưới đây:

  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 
      } 

Mã này không hoạt động bởi vì tôi tìm evertime B tiến hành trước khi A có thể hoàn thành. Về cơ bản tôi không biết nên sử dụng sự kiện nào.

Làm cách nào để hoàn thành mục tiêu của mình? Tôi có thể sử dụng những sự kiện nào để tôi có thể đồng bộ hóa xử lý B ngay sau khi kết thúc bằng A?

+2

Javascript là Không đồng bộ. Bạn cần tìm hiểu về callbacks ... thực hiện chức năng, sau khi hoàn thành gọi lại chức năng B ... – zipzit

+0

tùy thuộc vào trình duyệt bạn đang sử dụng và nếu việc bạn làm sẽ không được sử dụng thực sự sớm, và đặc biệt nếu đây là cho chính mình, tôi khuyên bạn nên học cách sử dụng 'fetch': http://updates.html5rocks.com/2015/03/introduction-to-fetch –

Trả lời

3

(Sau khi chỉnh sửa kéo dài), tôi khuyên bạn nên dành thời gian để hiểu bản chất của các cuộc gọi không đồng bộ trong JavaScript. Đây là một chút đọc được khuyến nghị. Asynchronous Programming in JavaScript Tôi nghĩ rằng đó là đủ đơn giản để hiểu những gì đang xảy ra. Lưu ý: Ngừng đọc tại "Nhập Mobl".

Trong JavaScript khi bạn gọi một hàm, hệ thống đặt hàm đó vào một 'hàng đợi' với một lệnh ẩn để tiếp tục và chạy nó ngay khi có thể. Nó làm điều đó cho mỗi và mọi cuộc gọi hàm. Trong trường hợp của bạn, bạn đang nói cho hệ thống để chạy A, sau đó chạy B. A đi trong hàng đợi, B đi trong hàng đợi. Chúng được gửi dưới dạng các hàm riêng lẻ. B xảy ra để chạy đầu tiên.

Đối với các chức năng bình thường, nếu bạn muốn điều khiển trình tự, bạn có thể lồng cuộc gọi hàm A trong cuộc gọi hàm B. Nhưng oops. Bạn đang sử dụng XMLHttpRequest, để hạn chế khả năng tùy chỉnh các chức năng của bạn. Đọc tiếp. Kiểm tra Ajax Patterns on the subject Xem đoạn văn cho "Cuộc gọi không đồng bộ". Hãy nhìn vào mã của bạn ...

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

Tôi nghĩ rằng sẽ đưa bạn đến đích, giả sử bạn không muốn có giải pháp jQuery.

Đối với người chỉ muốn một hệ thống hoạt động và không muốn hiểu ngôn ngữ tốt hơn, đây là giải pháp jquery ... Lưu ý cách gọi hàm B được lồng trong lời gọi hàm A. Lưu ý rằng thứ tự của tổ hợp này dựa trên sự hiện diện của thẻ thành công jQuery. Nếu không sử dụng jQuery, bạn sẽ phải lồng các hàm một cách thủ công nếu thích hợp.

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

Tôi sẽ nói, sẽ giúp bạn dễ dàng hơn trong việc sử dụng giao tiếp tốt hơn. Nếu bạn không thích một cái gì đó, sau đó nhà nước. Nếu bạn không hiểu điều gì đó, hãy yêu cầu làm rõ thêm hoặc chỉnh sửa tuyên bố vấn đề của bạn. Phản hồi là một điều tốt.

+4

Câu hỏi không được gắn thẻ jQuery, và câu trả lời này không giải thích được các vấn đề hoặc giải pháp được đề xuất. – Bergi

+0

Gee, tôi nghĩ rõ ràng rằng vấn đề là 98% hiểu về các cuộc gọi hàm javascript và 2% sử dụng XMLHttpRequest(). Đọc bình luận của tôi bên dưới câu hỏi ban đầu. Không rõ là ikis dự định không có giải pháp jQuery. Kiểm tra ý kiến ​​trở lại của mình để giải pháp của tôi .. ooops. Anh ấy chưa bao giờ đưa ra bất kỳ phản hồi nào cho câu trả lời tôi đã thực hiện ba tuần trước. Thay vào đó, anh ấy đã thêm một tiền thưởng (mà không bao giờ gửi một tin nhắn cho tôi? Er .. tại sao không?) Trên các thẻ ... bạn đã bao giờ thấy các câu hỏi với lựa chọn thẻ kém? (Ans. Tất cả thời gian) Ông có thể dễ dàng đề cập đến rqmt no-jquery trong câu hỏi của mình. – zipzit

+1

Chắc chắn. Nhưng câu trả lời của bạn không cung cấp bất kỳ sự hiểu biết nào về các cuộc gọi hàm (async), chỉ là một đoạn mã ví dụ jQuery. Một câu trả lời hợp lệ không cần phải bao gồm XHR, và có thể chứa jQuery; nhưng nó không phải dựa vào jQuery. – Bergi

11

Ok, vậy hãy bắt đầu với mã của bạn. Tôi đã thêm một vài nhận xét vào nó, vì vậy bây giờ bạn có thể hiểu nguồn gốc của sự cố:

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 
} 

Tôi hy vọng rằng bây giờ bạn có thể thấy nguồn gốc của vấn đề. Khi bạn chạy tập lệnh này, khi đó bạn bắt đầu yêu cầu không đồng bộ và sau đó bắt đầu ngay lập tức. Bây giờ bạn có thể chọn từ 2 cách.

Chạy yêu cầu tiếp theo từ gọi lại (được khuyến nghị)

Đó là cách tốt hơn. Vì vậy, bắt đầu yêu cầu đầu tiên (không đồng bộ) của bạn và trong trình xử lý sự kiện (nơi bạn thực hiện việc xử lý), bạn có thể bắt đầu yêu cầu tiếp theo. Tôi đã thực hiện một ví dụ bình luận ở đây: http://jsfiddle.net/5pt6j1mo/1/

(Bạn có thể làm điều đó mà không cần mảng - đó chỉ là một ví dụ)

Nếu bạn sử dụng cách này thì giao diện sẽ không đóng băng cho đến khi bạn đang chờ đợi để trả lời. Tất cả mọi thứ sẽ chịu trách nhiệm, do đó bạn có thể tương tác với trang web, bạn có thể tạo nút hủy vv

Synchronous AJAX (không khuyến khích)

tôi không khuyên bạn nên nó bởi vì "XMLHttpRequest Synchronous trên thread chính bị phản đối "trong Chrome, nhưng nếu bạn thực sự muốn thì bạn có thể thử sử dụng giải pháp này. Vì vậy, chức năng mở một của XMLHttpRequest có 3 đối số:

  • PHƯƠNG PHÁP: đó HTTP methid sử dụng
  • URL: mà URL để yêu cầu
  • ASYNC: yêu cầu không đồng bộ? Nếu sai sau đó nó sẽ được đồng bộ mà có nghĩa là sau khi bạn gọi .send(), nó sẽ tạm dừng thực hiện cho đến khi phản ứng trở lại.

Vì vậy, nếu bạn đặt tham số thứ ba thành FALSE thì bạn có thể dễ dàng thực hiện ... nhưng bạn không nên!

10

Dưới đây là một giải pháp thay thế, hoặc là sử dụng the fetch API hoặc promisify native XHR và vấn đề này trở nên đơn giản hơn nhiều:

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

Đây chỉ là bản địa như XHR, và nhiều đơn giản hơn nhiều để quản lý với những lời hứa.

+0

Wow. Rât thuận tiện. Không hoàn toàn chắc chắn tìm nạp đã sẵn sàng cho thời gian chính (bảng tương thích nói không được hỗ trợ trên Safari?) Nhưng cách mát mẻ. – zipzit

+0

Nó có thể dễ dàng được điền vào các trình duyệt chưa hỗ trợ –

Các vấn đề liên quan