Cách rõ ràng nhất để có được tiến độ của yêu cầu ajax JQuery là gì?


105

Trong javascript thuần túy rất đơn giản: chỉ cần đính kèm lệnh gọi lại {XMLHTTPRequest}.onprogress

var xhr = new XMLHttpRequest();

xhr.onprogress = function(e){
    if (e.lengthComputable)
        var percent = (e.loaded / e.total) * 100;
};

xhr.open('GET', 'http://www...', true);
xhr.onreadystatechange = function() {
    ...
};
xhr.send(null);

nhưng tôi đang thực hiện một trang web ajax tải xuống dữ liệu html bằng JQuery ( $.get()hoặc $.ajax()) và tôi đã tự hỏi đâu là cách tốt nhất để có được tiến trình của một yêu cầu để hiển thị nó với một thanh tiến trình nhỏ nhưng thật kỳ lạ, tôi không tìm bất cứ thứ gì hữu ích trong tài liệu JQuery ...


4
Cái này có vẻ đầy hứa hẹn dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5 cho html5
PSL

1
Ooh cảm ơn các bạn! nên cần phải ghi đè XHR .. điều lạ là tôi đã kiểm tra với Chrome Dev Công cụ cái gọi là jqXHRđối tượng (wrapper của đối tượng XHR trả về bởi $.ajax()) và tìm thấy một progressthuộc tính trong nó (cùng với abort, complete, success, vv), nhưng trong tài liệu JQuery, điều này bị thiếu: api.jquery.com/jQuery.ajax/#jqXHR
guari

3
github.com/englercj/jquery-ajax-progress tôi sử dụng này và nó hoàn toàn giống như câu trả lời khác nhưng tôi prefere có chung nhiều thứ
KeizerBridge

Câu trả lời:


139

Một cái gì đó như thế này cho $.ajax(mặc dù chỉ HTML5):

$.ajax({
    xhr: function() {
        var xhr = new window.XMLHttpRequest();
        xhr.upload.addEventListener("progress", function(evt) {
            if (evt.lengthComputable) {
                var percentComplete = evt.loaded / evt.total;
                //Do something with upload progress here
            }
       }, false);

       xhr.addEventListener("progress", function(evt) {
           if (evt.lengthComputable) {
               var percentComplete = evt.loaded / evt.total;
               //Do something with download progress
           }
       }, false);

       return xhr;
    },
    type: 'POST',
    url: "/",
    data: {},
    success: function(data){
        //Do something on success
    }
});

1
Có vẻ hứa hẹn, nhưng làm thế nào điều này có thể hoạt động? Toàn bộ quy trình bao gồm ba bước - gửi một yêu cầu, xử lý yêu cầu trong phần phụ trợ để tạo ra một số dữ liệu và trả lại nó. Làm thế nào phía khách hàng có thể biết được những gì đang được thực hiện trong phần phụ trợ và sẽ mất bao nhiêu thời gian để có thể tính toán tiến trình?
SexyBeast

1
Tiêu đề phản hồi HTTP cho chúng ta biết có bao nhiêu byte dự kiến, tiến trình này chỉ đơn giản là đếm số byte đã được nhận cho đến nay. Nó sẽ ở lại cho đến khi không đáp ứng HTTP được thực sự được gửi
J. Allen

2
Nó chỉ hoạt động trên POST, không nhận được GET và những người khác?
Raz

43

jQuery đã thực hiện các hứa hẹn, vì vậy tốt hơn nên sử dụng công nghệ này và không chuyển logic sự kiện sang optionstham số. Tôi đã tạo một plugin jQuery bổ sung lời hứa tiến độ và bây giờ nó dễ sử dụng giống như các lời hứa khác:

$.ajax(url)
  .progress(function(){
    /* do some actions */
  })
  .progressUpload(function(){
    /* do something on uploading */
  });

Kiểm tra nó tại github


Tôi thích cách bạn sử dụng nhà máy IFI. Tôi không biết kỹ thuật đó!
CodeArtist

Đây hiện là giải pháp tốt nhất được đề xuất ở đây.
không nguyên tử vào

2
Giải pháp làm việc và thanh lịch nhưng bạn có thể biết rằng nó có thể phá vỡ mã hiện tại của bạn vì nó phá vỡ tất cả các lệnh gọi tới .success và .error không dùng nữa. Nó cũng loại bỏ tất cả các thuộc tính không chuẩn mà bạn đặt trên đối tượng jqXHR. Nó cũng không cung cấp ngữ cảnh thành "this" cho lệnh gọi lại uploadProgress (có thể giống với tiến trình nhưng không được kiểm tra) vì nó được thực hiện cho tất cả các hứa hẹn tiêu chuẩn cho jqXHR. Vì vậy, bạn sẽ cần phải chuyển ngữ cảnh trong một lần đóng.
thẳng thắn

4
Tôi gặp lỗi: TypeError: $.ajax(...).progress(...).progressUpload is not a function.... Vấn đề là gì?
Universal Grasp

@UniversalGrasp xin chào, vui lòng mở một vấn đề trên github và cung cấp thông tin về những gì bạn đã làm. Thư viện này không được cập nhật cho các lứa tuổi :) có thể một cái gì đó đã thay đổi trong jQuery riêng của mình
likerRr

5

Tôi đã thử về ba cách khác nhau để chặn việc xây dựng đối tượng Ajax:

  1. Lần thử đầu tiên của tôi được sử dụng xhrFields, nhưng điều đó chỉ cho phép một người nghe, chỉ đính kèm với tiến trình tải xuống (không tải lên) và yêu cầu những gì có vẻ giống như sao chép và dán không cần thiết.
  2. Lần thử thứ hai của tôi đã gắn một progresshàm vào lời hứa trả về, nhưng tôi phải duy trì mảng trình xử lý của riêng mình. Tôi không thể tìm thấy một đối tượng tốt để đính kèm các trình xử lý vì một nơi tôi muốn truy cập vào XHR và một nơi khác tôi có quyền truy cập vào jQuery XHR, nhưng tôi chưa bao giờ có quyền truy cập vào đối tượng hoãn lại (chỉ là lời hứa của nó).
  3. Lần thử thứ ba của tôi đã cho tôi quyền truy cập trực tiếp vào XHR để đính kèm các trình xử lý, nhưng lại yêu cầu nhiều mã sao chép và dán.
  4. Tôi đã kết thúc lần thử thứ ba của mình và thay thế jQuery ajaxbằng của riêng tôi. Thiếu sót tiềm ẩn duy nhất là bạn không thể sử dụng xhr()cài đặt của riêng mình nữa. Bạn có thể cho phép điều đó bằng cách kiểm tra xem có phải options.xhrlà một chức năng hay không.

Tôi thực sự gọi promise.progresshàm của mình xhrProgressđể tôi có thể dễ dàng tìm thấy nó sau này. Bạn có thể muốn đặt tên khác cho nó để tách phần nghe tải lên và tải xuống. Tôi hy vọng điều này sẽ giúp ích cho ai đó ngay cả khi người đăng ban đầu đã có những gì anh ta cần.

(function extend_jQuery_ajax_with_progress( window, jQuery, undefined )
{
var $originalAjax = jQuery.ajax;
jQuery.ajax = function( url, options )
{
    if( typeof( url ) === 'object' )
    {options = url;url = undefined;}
    options = options || {};

    // Instantiate our own.
    var xmlHttpReq = $.ajaxSettings.xhr();
    // Make it use our own.
    options.xhr = function()
    {return( xmlHttpReq );};

    var $newDeferred = $.Deferred();
    var $oldPromise = $originalAjax( url, options )
    .done( function done_wrapper( response, text_status, jqXHR )
    {return( $newDeferred.resolveWith( this, arguments ));})
    .fail( function fail_wrapper( jqXHR, text_status, error )
    {return( $newDeferred.rejectWith( this, arguments ));})
    .progress( function progress_wrapper()
    {
        window.console.warn( "Whoa, jQuery started actually using deferred progress to report Ajax progress!" );
        return( $newDeferred.notifyWith( this, arguments ));
    });

    var $newPromise = $newDeferred.promise();
    // Extend our own.
    $newPromise.progress = function( handler )
    {
        xmlHttpReq.addEventListener( 'progress', function download_progress( evt )
        {
            //window.console.debug( "download_progress", evt );
            handler.apply( this, [evt]);
        }, false );
        xmlHttpReq.upload.addEventListener( 'progress', function upload_progress( evt )
        {
            //window.console.debug( "upload_progress", evt );
            handler.apply( this, [evt]);
        }, false );
        return( this );
    };
    return( $newPromise );
};
})( window, jQuery );

Vì vậy, tôi vừa thử triển khai giải pháp của bạn nhưng mã này hơi quá chuyên nghiệp để tôi hiểu - làm cách nào để sử dụng nó? Tôi sao chép, dán toàn bộ mã của bạn trước tài liệu của tôi. Đã và đã thử làm $.ajax({ ... }).progress(function(evl) { console.log(evl); });nhưng không có gì xảy ra. Bạn có thể giúp tôi được không? :)
Patrick DaVader

Bạn đang sử dụng phiên bản jQuery nào?
Flo Schild

@FloSchild, vui lòng không chỉnh sửa mã của tôi chỉ vì lợi ích của tùy chọn định dạng của riêng bạn.
MarkMYoung

3

jQuery có một AjaxSetup()chức năng cho phép bạn đăng ký các trình xử lý ajax toàn cục, chẳng hạn như beforeSendcompletecho tất cả các lệnh gọi ajax cũng như cho phép bạn truy cập xhrđối tượng để thực hiện tiến trình mà bạn đang tìm kiếm


2
Cảm ơn các liên kết. Bạn có thể bao gồm một ví dụ trong câu trả lời của bạn?
Michael Scheper

$ .ajaxSetup ({xhr: function () {console.log ('setup XHR ...');}});
Flo Schild

7
Và một ví dụ trả lời câu hỏi? Tôi e rằng tôi không thể ủng hộ một câu trả lời khiến tôi phải loay hoay và đọc rất nhiều, đặc biệt khi trang được liên kết không nói gì về tiến trình. Thành thực mà nói, tôi hoài nghi về điều này, đặc biệt trong bối cảnh báo trên trang đó, nói rằng 'Lưu ý: chức năng gọi lại toàn cầu nên được thiết lập với methods- Ajax xử lý sự kiện toàn cầu của mình .ajaxStart(), .ajaxStop(), .ajaxComplete(), .ajaxError(), .ajaxSuccess(), .ajaxSend()-rather hơn trong lựa chọn đối tượng cho $.ajaxSetup(). ' < api.jquery.com/jQuery.ajaxSetup/#entry-longdesc >
Michael Scheper

1
Từ tài liệu : Đặt giá trị mặc định cho các yêu cầu Ajax trong tương lai. Việc sử dụng nó không được khuyến khích.
Oyvind

-1

http://www.htmlgoodies.com/beyond/php/show-progress-report-for-long-running-php-scripts.html

Tôi đã tìm kiếm một giải pháp tương tự và thấy giải pháp này đã được sử dụng đầy đủ.

var es;

function startTask() {
    es = new EventSource('yourphpfile.php');

//a message is received
es.addEventListener('message', function(e) {
    var result = JSON.parse( e.data );

    console.log(result.message);       

    if(e.lastEventId == 'CLOSE') {
        console.log('closed');
        es.close();
        var pBar = document.getElementById('progressor');
        pBar.value = pBar.max; //max out the progress bar
    }
    else {

        console.log(response); //your progress bar action
    }
});

es.addEventListener('error', function(e) {
    console.log('error');
    es.close();
});

}

và đầu ra máy chủ của bạn

header('Content-Type: text/event-stream');
// recommended to prevent caching of event data.
header('Cache-Control: no-cache'); 

function send_message($id, $message, $progress) {
    $d = array('message' => $message , 'progress' => $progress); //prepare json

    echo "id: $id" . PHP_EOL;
    echo "data: " . json_encode($d) . PHP_EOL;
    echo PHP_EOL;

   ob_flush();
   flush();
}


//LONG RUNNING TASK
 for($i = 1; $i <= 10; $i++) {
    send_message($i, 'on iteration ' . $i . ' of 10' , $i*10); 

    sleep(1);
 }

send_message('CLOSE', 'Process complete');

Điều này cho thấy tiến trình của một tập lệnh PHP đang chạy, không phải của một cuộc gọi AJAX.
Sinus Mackowaty

-3

Làm theo các bước để hiển thị Tiến trình của Yêu cầu Ajax:

  1. Tạo Spinner bằng Html & CSS hoặc sử dụng Bootstrap Spinner.
  2. Hiển thị Spinner khi người dùng cuối yêu cầu Dữ liệu AJAX cho vòng lặp vô hạn hoặc cho thời gian giới hạn ngưỡng.
  3. Vì vậy, sau khi kết quả THÀNH CÔNG / LỖI của Yêu cầu AJAX, hãy xóa Spinner hiện đang hiển thị và hiển thị kết quả của bạn.

Để dễ dàng hơn, tôi khuyên bạn nên sử dụng Lớp JS để Tự động Hiển thị & Ẩn con quay cho mục đích này.

Tôi hi vọng cái này giúp được!


2
Đó không phải là "nhận được tiến độ", chỉ hiển thị một hình ảnh động "đang chờ đợi".
Sinus Mackowaty
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.