Làm cách nào để bạn lưu vào bộ nhớ cache một hình ảnh trong Javascript


83

Bạn bè của tôi và tôi đang làm việc trên một trang web nơi chúng tôi muốn lưu vào bộ nhớ cache những hình ảnh nhất định để hiển thị chúng nhanh hơn trong tương lai. Tôi có hai câu hỏi chính:

  1. Làm cách nào để bạn lưu vào bộ nhớ cache một hình ảnh?
  2. Làm thế nào để bạn sử dụng một hình ảnh sau khi nó đã được lưu vào bộ nhớ cache? (và chỉ để xác minh, nếu một hình ảnh được lưu trong bộ nhớ cache trên trang A, thì có thể gọi nó từ bộ nhớ cache để sử dụng nó trên trang B, phải không?)

Ngoài ra, có thể đặt khi nào phiên bản được lưu trong bộ nhớ cache của hình ảnh sẽ hết hạn không?

Sẽ được đánh giá cao nếu một ví dụ và / hoặc liên kết đến một trang mô tả thêm điều này được bao gồm.

Chúng tôi ổn khi sử dụng Javascript thô hoặc phiên bản jQuery.


12
Bạn không. Trình duyệt không.
Pointy

trình duyệt có tự động lưu hình ảnh vào bộ nhớ cache không?
Logan Besecker

8
@Logan: Có, trình duyệt tự động lưu trữ hình ảnh vào bộ nhớ cache, miễn là máy chủ của bạn gửi các tiêu đề cần thiết để cho trình duyệt biết rằng có thể lưu vào bộ nhớ cache an toàn. (Những tiêu đề cũng có thể nói với các trình duyệt thời gian hết hạn, mà là một phần của câu hỏi của bạn.)
icktoofay

làm cách nào để xác minh rằng trình duyệt của tôi đang gửi các tiêu đề cần thiết?
Logan Besecker

1
@LoganBesecker Bạn có thể kiểm tra Tiêu đề phản hồi trong phần Mạng của các công cụ phát triển trình duyệt của bạn.
jlaceda

Câu trả lời:


131

Khi hình ảnh đã được tải theo bất kỳ cách nào vào trình duyệt, nó sẽ nằm trong bộ nhớ cache của trình duyệt và sẽ tải nhanh hơn nhiều vào lần sử dụng tiếp theo cho dù việc sử dụng đó là trong trang hiện tại hay trong bất kỳ trang nào khác miễn là hình ảnh đó được sử dụng trước khi hết hạn khỏi bộ nhớ cache của trình duyệt.

Vì vậy, để lọc trước hình ảnh, tất cả những gì bạn phải làm là tải chúng vào trình duyệt. Nếu bạn muốn xử lý trước một loạt hình ảnh, có lẽ tốt nhất là bạn nên làm điều đó với javascript vì nó thường không giữ tải trang khi thực hiện từ javascript. Bạn có thể làm như thế này:

function preloadImages(array) {
    if (!preloadImages.list) {
        preloadImages.list = [];
    }
    var list = preloadImages.list;
    for (var i = 0; i < array.length; i++) {
        var img = new Image();
        img.onload = function() {
            var index = list.indexOf(this);
            if (index !== -1) {
                // remove image from the array once it's loaded
                // for memory consumption reasons
                list.splice(index, 1);
            }
        }
        list.push(img);
        img.src = array[i];
    }
}

preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"]);

Hàm này có thể được gọi bao nhiêu lần tùy thích và mỗi lần, nó sẽ chỉ thêm nhiều hình ảnh vào bộ đệm trước.

Khi các hình ảnh đã được tải trước như thế này qua javascript, trình duyệt sẽ có chúng trong bộ nhớ cache của nó và bạn chỉ có thể tham khảo các URL bình thường ở những nơi khác (trong các trang web của bạn) và trình duyệt sẽ tìm nạp URL đó từ bộ nhớ cache của nó thay vì qua mạng lưới.

Cuối cùng theo thời gian, bộ nhớ cache của trình duyệt có thể lấp đầy và quăng những thứ cũ nhất chưa được sử dụng trong một thời gian. Vì vậy, cuối cùng, hình ảnh sẽ bị xóa khỏi bộ nhớ cache, nhưng chúng sẽ ở đó trong một thời gian (tùy thuộc vào dung lượng bộ nhớ cache và mức độ duyệt web khác được thực hiện). Mỗi khi hình ảnh thực sự được tải lại trước hoặc được sử dụng trong một trang web, nó sẽ tự động làm mới vị trí của chúng trong bộ nhớ cache của trình duyệt để chúng ít có khả năng bị xóa khỏi bộ nhớ cache hơn.

Bộ nhớ đệm của trình duyệt là bộ nhớ đệm chéo trang nên nó hoạt động cho bất kỳ trang nào được tải vào trình duyệt. Vì vậy, bạn có thể chọn trước ở một nơi trong trang web của mình và bộ nhớ cache của trình duyệt sau đó sẽ hoạt động cho tất cả các trang khác trên trang web của bạn.


Khi cắt bỏ như trên, hình ảnh được tải không đồng bộ nên chúng sẽ không chặn việc tải hoặc hiển thị trang của bạn. Tuy nhiên, nếu trang của bạn có nhiều hình ảnh riêng, thì những hình ảnh bộ đệm trước này có thể cạnh tranh về băng thông hoặc kết nối với hình ảnh được hiển thị trong trang của bạn. Thông thường, đây không phải là một vấn đề đáng chú ý, nhưng trên kết nối chậm, việc cắt bỏ này có thể làm chậm quá trình tải trang chính. Nếu hình ảnh tải trước được tải sau cùng là OK, thì bạn có thể sử dụng một phiên bản của chức năng sẽ đợi để bắt đầu tải trước cho đến khi tất cả các tài nguyên trang khác đã được tải xong.

function preloadImages(array, waitForOtherResources, timeout) {
    var loaded = false, list = preloadImages.list, imgs = array.slice(0), t = timeout || 15*1000, timer;
    if (!preloadImages.list) {
        preloadImages.list = [];
    }
    if (!waitForOtherResources || document.readyState === 'complete') {
        loadNow();
    } else {
        window.addEventListener("load", function() {
            clearTimeout(timer);
            loadNow();
        });
        // in case window.addEventListener doesn't get called (sometimes some resource gets stuck)
        // then preload the images anyway after some timeout time
        timer = setTimeout(loadNow, t);
    }

    function loadNow() {
        if (!loaded) {
            loaded = true;
            for (var i = 0; i < imgs.length; i++) {
                var img = new Image();
                img.onload = img.onerror = img.onabort = function() {
                    var index = list.indexOf(this);
                    if (index !== -1) {
                        // remove image from the array once it's loaded
                        // for memory consumption reasons
                        list.splice(index, 1);
                    }
                }
                list.push(img);
                img.src = imgs[i];
            }
        }
    }
}

preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"], true);
preloadImages(["url99.jpg", "url98.jpg"], true);

Trong ví dụ này, bạn đang tạo một đối tượng Hình ảnh mới cho mỗi url. Nếu bạn đặt biến img bên ngoài vòng lặp và chỉ cần cập nhật các src, nó nên có tác dụng tương tự và cắt giảm nguồn lực
cadlac

1
@cadlac - Nhưng để chắc chắn rằng trình duyệt sẽ thực sự tải xuống và lưu vào bộ nhớ cache của từng hình ảnh, bạn sẽ phải đợi cho đến khi tải xong một hình ảnh trước khi đặt thuộc tính .src mới. Nếu không, trình duyệt chỉ có thể dừng quá trình tải xuống trước đó và không bao giờ lưu vào bộ nhớ cache thành công.
jfriend00

Nó dường như hoạt động trên các phiên bản trình duyệt mới hơn mà không cần chờ đợi, nhưng bạn đã làm được một điều tốt. Tôi sẽ phải thử nó ra trên một số trình duyệt cũ để xem nó tương thích :)
cadlac

@cadlac - không cần. Tôi đã cập nhật mã để xóa Image()phần tử khỏi danh sách khi hình ảnh tải xong. Sẽ an toàn hơn nếu bạn đợi cho đến khi hình ảnh tải xong.
jfriend00

1
Tôi đã thêm một phiên bản khác của tập lệnh chờ cho đến khi các tài nguyên tài liệu khác được tải xong để tải trước hình ảnh không cạnh tranh về băng thông với việc tải tài nguyên trang hiển thị.
jfriend00

13

như @Pointy đã nói rằng bạn không lưu hình ảnh vào bộ nhớ cache bằng javascript, trình duyệt sẽ làm điều đó. vì vậy đây có thể là những gì bạn yêu cầu và có thể không ... nhưng bạn có thể tải trước hình ảnh bằng javascript. Bằng cách đặt tất cả hình ảnh bạn muốn tải trước vào một mảng và đặt tất cả hình ảnh trong mảng đó vào các phần tử img ẩn, bạn tải trước (hoặc bộ nhớ cache) hình ảnh một cách hiệu quả.

var images = [
'/path/to/image1.png',
'/path/to/image2.png'
];

$(images).each(function() {
var image = $('<img />').attr('src', this);
});

2
liệu có thể tải trước một hình ảnh trên một trang (mà không hiển thị nó), sau đó hiển thị nó trên trang tiếp theo?
Logan Besecker

2
Theo hiểu biết của tôi, nếu bạn tải trước một hình ảnh trên một trang, nó sẽ được nhập vào bộ nhớ cache của trình duyệt và sau đó sẽ hiển thị nhanh hơn trên bất kỳ trang nào khác. nếu điều này là sai, ai đó xin vui lòng sửa cho tôi.
Trav McKinney

3

Có một số điều bạn có thể xem xét:

Tải trước hình ảnh của bạn
Đặt thời gian lưu trong bộ nhớ cache trong tệp .htaccess
Kích thước tệp của hình ảnh và mã hóa base64 chúng.

Tải trước: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

Bộ nhớ đệm: http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html

Có một vài suy nghĩ khác nhau đối với mã hóa base64, một số người nói rằng http yêu cầu băng thông giảm, trong khi những người khác nói rằng tải "cảm nhận" tốt hơn. Tôi sẽ để nó trong không khí.


3

Mặc dù câu hỏi của bạn nói "sử dụng javascript", bạn có thể sử dụng prefetchthuộc tính của thẻ liên kết để tải trước bất kỳ nội dung nào. Kể từ khi viết bài này (ngày 10 tháng 8 năm 2016), nó không được hỗ trợ trong Safari, nhưng ở khá nhiều nơi khác:

<link rel="prefetch" href="(url)">

Thông tin thêm về hỗ trợ tại đây: http://caniuse.com/#search=prefetch

Lưu ý rằng IE 9,10 không được liệt kê trong caniusema trận vì Microsoft đã ngừng hỗ trợ cho chúng.

Vì vậy, nếu bạn thực sự gặp khó khăn trong việc sử dụng javascript, bạn có thể sử dụng jquery để thêm động các phần tử này vào trang của mình ;-)


1
Tốt đẹp tốt đẹp tốt đẹp!
Bhargav Nanekalva

2

Thêm để hoàn thiện câu trả lời: tải trước bằng HTML

<link rel="preload" href="bg-image-wide.png" as="image">

Các tính năng tải trước khác tồn tại, nhưng không có tính năng nào hoàn toàn phù hợp với mục đích như <link rel="preload">:

  • <link rel="prefetch">đã được hỗ trợ trong các trình duyệt trong một thời gian dài, nhưng nó dành cho việc tìm nạp trước các tài nguyên sẽ được sử dụng trong lần điều hướng / tải trang tiếp theo (ví dụ: khi bạn chuyển đến trang tiếp theo). Điều này là tốt, nhưng không hữu ích cho trang hiện tại! Ngoài ra, các trình duyệt sẽ ưu tiên tài nguyên tìm nạp trước thấp hơn so với tải trước - trang hiện tại quan trọng hơn trang tiếp theo. Xem Câu hỏi thường gặp về tìm nạp trước Liên kết để biết thêm chi tiết.
  • <link rel="prerender">hiển thị một trang web cụ thể trong nền, tăng tốc độ tải của nó nếu người dùng điều hướng đến nó. Do có khả năng lãng phí băng thông của người dùng, thay vào đó, Chrome xử lý kết xuất trước như một tìm nạp trước NoState.
  • <link rel="subresource"> đã được hỗ trợ trong Chrome một thời gian trước và được dự định giải quyết vấn đề tương tự như tải trước, nhưng nó có một vấn đề: không có cách nào để tính mức độ ưu tiên cho các mục (như không tồn tại trước đó), vì vậy tất cả đã được tìm nạp với mức độ ưu tiên khá thấp.

Có một số trình tải tài nguyên dựa trên tập lệnh, nhưng chúng không có bất kỳ sức mạnh nào đối với hàng đợi ưu tiên tìm nạp của trình duyệt và có cùng nhiều vấn đề về hiệu suất.

Nguồn: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content


Đây phải là câu trả lời được chấp nhận. Cảm ơn!
Renan Coelho

1

Tôi có một câu trả lời tương tự cho việc tải trước hình ảnh không đồng bộ qua JS. Tải chúng động cũng giống như tải chúng bình thường. chúng sẽ lưu vào bộ nhớ cache.

đối với bộ nhớ đệm, bạn không thể kiểm soát trình duyệt nhưng bạn có thể đặt nó thông qua máy chủ. nếu bạn cần tải một tài nguyên thực sự mới theo yêu cầu, bạn có thể sử dụng kỹ thuật buster bộ nhớ cache để buộc tải một tài nguyên mới.


1

Tôi sử dụng một kỹ thuật tương tự để lazyload hình ảnh, nhưng không thể không nhận thấy rằng Javascript không truy cập vào bộ nhớ cache của trình duyệt trong lần tải đầu tiên.

Ví dụ của tôi:

Tôi có một biểu ngữ xoay trên trang chủ của mình với 4 hình ảnh, thanh trượt đợi 2 giây, so với javascript tải hình ảnh tiếp theo, đợi 2 giây, v.v.

Những hình ảnh này có các url duy nhất thay đổi bất cứ khi nào tôi sửa đổi chúng, vì vậy chúng nhận được các tiêu đề bộ nhớ đệm sẽ lưu vào bộ nhớ đệm trong trình duyệt trong một năm.

max-age: 31536000, public

Bây giờ khi tôi mở Chrome Devtools và đảm bảo rằng tùy chọn 'Tắt bộ nhớ cache' không hoạt động và tải trang lần đầu tiên (sau khi xóa bộ nhớ cache), tất cả hình ảnh sẽ được tìm nạp và có trạng thái 200. Sau một chu kỳ đầy đủ của tất cả các hình ảnh trong biểu ngữ, yêu cầu mạng dừng lại và các hình ảnh được lưu trong bộ nhớ cache được sử dụng.

Bây giờ khi tôi làm mới thường xuyên hoặc truy cập trang con và nhấp lại, hình ảnh trong bộ nhớ cache dường như bị bỏ qua. Tôi sẽ thấy thông báo màu xám "từ bộ nhớ cache trên đĩa" trong tab Mạng của các nhà phát triển Chrome. Thay vào đó, tôi thấy các yêu cầu trôi qua sau mỗi hai giây với vòng tròn trạng thái Màu xanh lá cây thay vì màu xám, tôi thấy dữ liệu đang được chuyển, vì vậy tôi có ấn tượng rằng bộ nhớ cache hoàn toàn không được truy cập từ javascript. Nó chỉ đơn giản là tìm nạp hình ảnh mỗi khi trang được tải.

Vì vậy, mỗi yêu cầu đến trang chủ sẽ kích hoạt 4 yêu cầu bất kể chính sách bộ nhớ đệm của hình ảnh.

Xem xét các yếu tố trên cùng với tiêu chuẩn http2 mới mà hầu hết các máy chủ web và trình duyệt hiện nay đều hỗ trợ, tôi nghĩ tốt hơn nên ngừng sử dụng lazyloading vì http2 sẽ tải tất cả các hình ảnh gần như đồng thời.

Nếu đây là một lỗi trong Chrome Devtools, điều này thực sự gây ngạc nhiên cho tôi là chưa ai nhận ra điều này. ;)

Nếu điều này là đúng, việc sử dụng lazyloading chỉ làm tăng việc sử dụng băng thông.

Hãy sửa lại cho tôi nếu tôi sai. :)



0

Tôi luôn thích sử dụng ví dụ được đề cập trong Konva JS: Sự kiện hình ảnh để tải hình ảnh.

  1. Bạn cần có danh sách URL hình ảnh dưới dạng đối tượng hoặc mảng, ví dụ:

    var sources = { lion: '/assets/lion.png', monkey: '/assets/monkey.png' };

  2. Xác định định nghĩa Hàm, nơi nó nhận danh sách URL hình ảnh và một hàm gọi lại trong danh sách đối số của nó, vì vậy khi nó tải xong hình ảnh, bạn có thể bắt đầu thực hiện trên trang web của mình:

    function loadImages(sources, callback) {
                var images = {};
                var loadedImages = 0;
                var numImages = 0;
                for (var src in sources) {
                    numImages++;
                }
                for (var src in sources) {
                    images[src] = new Image();
                    images[src].onload = function () {
                        if (++loadedImages >= numImages) {
                            callback(images);
                        }
                    };
                    images[src].src = sources[src];
                }
            }

  1. Cuối cùng, bạn cần gọi hàm. Bạn có thể gọi nó chẳng hạn từ jQuery's Document Ready

$(document).ready(function (){ loadImages(sources, buildStage); });


0

Ngày nay, có một kỹ thuật mới được google đề xuất để lưu vào bộ nhớ cache và cải thiện quá trình hiển thị hình ảnh của bạn:

  1. Bao gồm tệp JavaScript Lazysizes: lazysizes.js
  2. Thêm tệp vào tệp html mà bạn muốn sử dụng: <script src="lazysizes.min.js" async></script>
  3. Thêm lazyloadlớp vào hình ảnh của bạn: <img data-src="images/flower3.png" class="lazyload" alt="">
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.