2013-07-03 26 views
18

Tôi đang sử dụng FileReader để hiển thị hình ảnh cục bộ trong ứng dụng Backbone. Các hình ảnh nhỏ hơn được hiển thị ngay lập tức mà không gặp bất kỳ sự cố nào, nhưng khi hình ảnh có kích thước từ vài megabyte trở lên, phải mất Chrome 2 hoặc 3 giây để tải hình ảnh (trên MacBook Pro hoàn toàn mới với RAM 8 GB).Sự cố hiệu suất khi tải hình ảnh cục bộ vào trình duyệt

Như đã nêu trong các nhận xét, hình ảnh lớn tải ngay lập tức trong this File API tutorial, vì vậy vấn đề không phải là với FileReader mà đúng hơn là với việc triển khai cụ thể của tôi trong Backbone.

Tôi đã bao gồm mô hình Backbone có liên quan và xem bên dưới. Dưới đây là phác thảo của logic:

  1. Mô hình tạo một đường dẫn tệp mới được chuyển.
  2. Khi tệp được tải, Image được tạo và src của Image được đặt thành URL dữ liệu được cung cấp bởi FileReader.
  3. Khi hình ảnh đã được tải, mô hình được cập nhật với chiều rộng và chiều cao của hình ảnh (được sử dụng ở nơi khác trong ứng dụng) và thuộc tính initialized của mô hình được đặt thành true (do đó kích hoạt sự kiện change trên mô hình).
  4. Khi chế độ xem phát hiện sự kiện change trên mô hình, hàm render được gọi, thay thế hình nền của div bằng URL dữ liệu.

Backbone Mẫu

var PhotoModel = Backbone.Model.extend({ 

    initialize: function() { 
    this.set({"available": true}); 
    this.initialized = false; 
    if (this.get("file")) { 
     this.uploadPhoto(); 
    } 
    }, 

    uploadPhoto: function() { 
    var file = this.get("file"); 
    var reader = new FileReader(); 
    var model = this; 
    reader.onload = function(event) { 
     var image = new Image(); 
     image.onload = function() { 
     model.set({width: this.width, height: this.height}); 
     model.set("initialized", true); 
     }; 
     image.src = event.target.result; 
     model.set("dataURL", event.target.result); 
    } 
    reader.readAsDataURL(file); 
    }, 
}); 

Backbone Xem

var PhotoFormView = Backbone.View.extend({ 

    className: "photo-form", 

    initialize: function() { 
    this.listenTo(this.model, "change", this.render); 
    this.render(); 
    }, 

    render: function() { 
    $(this.el).find(".photo").css({"background-image": "url(" + this.model.get("dataURL") + ")"}); 
    }, 
}); 

Dưới đây là một ảnh chụp màn hình của timeline Chrome. Sự chậm trễ lớn nhất dường như xảy ra giữa yêu cầu URL dữ liệu và sự kiện tải (điều này chiếm khoảng 0,5 giây). Tôi không chắc chắn những gì "tính toán lại phong cách" là tất cả về. Tôi cũng không chắc chắn tại sao có rất nhiều sự kiện sơn (nó xuất hiện để được dựng hình trong khu vực thanh cuộn).

Chrome Timeline

SOLUTION

tôi đã giả định rằng trình duyệt sẽ có thể tự nhiên thay đổi kích thước hình ảnh một cách hiệu quả hơn bất kỳ giải pháp JavaScript, nhưng giả định này là sai. Bằng cách đổi kích thước hình ảnh trước khi chúng được hiển thị, tôi có thể giảm độ trễ xuống khoảng 50 mili giây. Tôi đã sử dụng plugin nguồn mở có tên là JavaScript Load Image để xử lý việc tải và thay đổi kích thước hình ảnh (nó sử dụng thẻ HTML5 canvas). Đây là mô hình Backbone đã sửa đổi của tôi:

var PhotoModel = Backbone.Model.extend({ 

    initialize: function() { 
    this.set({available: true}); 
    this.set({initialized: false}); 
    if (this.get("file")) { 
     this.uploadPhoto(); 
    } 
    }, 

    uploadPhoto: function() { 
    var model = this; 
    loadImage(this.get("file"), function (img) { 
     model.set({img: img}); 
     model.set({initialized: true}); 
    }, {maxHeight: 344}); 
    }, 
}); 

Trả lời

7

Tôi đã gặp phải vấn đề tương tự khi tải hình ảnh lớn bằng FileReader. Nếu bạn không có kế hoạch hiển thị chúng ở kích thước đầy đủ, có vẻ như giải pháp thay thế liên quan đến việc chia tỷ lệ hình ảnh trước khi hiển thị hình ảnh bằng yếu tố canvas.

Sau khi kết hợp thành công với việc triển khai của riêng tôi, tôi đã chọn sử dụng JavaScript Load Image (giấy phép MIT) và tùy chọn maxWidth, giải quyết vấn đề này và nhiều vấn đề khác (không xác thực).

Hãy thử xem the demo và xem liệu hình ảnh của bạn có tải độc đáo hay không.

+1

Đây chính xác là vấn đề. Tôi đã giả định rằng trình duyệt sẽ hiệu quả hơn trong việc thay đổi kích thước hình ảnh một cách nguyên bản hơn là gọi một giải pháp JavaScript. Tuy nhiên, đây không phải là trường hợp. Bằng cách thay đổi kích thước hình ảnh trước khi nó được hiển thị, tôi đã loại bỏ hoàn toàn độ trễ. Plugin bạn đề xuất là hoàn toàn hoàn hảo cho trường hợp này. Cảm ơn! –

+0

Tôi rất vui vì đã làm việc cho bạn, kudo đến https://github.com/blueimp vì công việc khó khăn! – lazd

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