Javascript'te bir resmi nasıl önbelleğe alırsınız


84

Arkadaşlarım ve ben, ileride daha hızlı görüntülemek için belirli resimleri önbelleğe almak istediğimiz bir web sitesi üzerinde çalışıyoruz. İki ana sorum var:

  1. Bir görüntüyü nasıl önbelleğe alırsınız?
  2. Önbelleğe alındıktan sonra bir resmi nasıl kullanırsınız? (ve sadece doğrulamak için, bir görüntü A sayfasında önbelleğe alınmışsa, onu B sayfasında kullanmak için önbellekten çağırmak mümkündür, değil mi?

Ayrıca, görüntünün önbelleğe alınmış sürümünün ne zaman sona ereceğini ayarlamak mümkün mü?

Bunu daha ayrıntılı olarak açıklayan bir sayfaya bir örnek ve / veya bir bağlantının dahil edilmesi çok takdir edilecektir.

Ham Javascript veya jQuery sürümünü kullanmakta sorun yok.


12
Yapmıyorsun. Tarayıcı yapar.
Sivri

tarayıcı resimleri otomatik olarak önbelleğe alıyor mu?
Logan Besecker

8
@Logan: Evet, sunucunuzun tarayıcıya önbelleğe almanın güvenli olduğunu bildirmek için gerekli başlıkları göndermesi koşuluyla, tarayıcı görüntüleri otomatik olarak önbelleğe alır. (Bu başlıklar ayrıca tarayıcıya sorunuzun bir parçası olan sona erme süresini de söyleyebilir.)
icktoofay

tarayıcımın gerekli başlıkları gönderdiğini nasıl doğrulayabilirim?
Logan Besecker

1
@LoganBesecker Tarayıcınızın geliştirme araçlarının Ağ bölümünde Yanıt Başlıkları'nı kontrol edebilirsiniz.
jlaceda

Yanıtlar:


133

Bir resim tarayıcıya herhangi bir şekilde yüklendikten sonra, tarayıcı önbelleğinde olacak ve bir sonraki kullanımda, bu kullanım mevcut sayfada veya resim olduğu sürece başka herhangi bir sayfada çok daha hızlı yüklenecektir. tarayıcı önbelleğinden süresi dolmadan önce kullanılır.

Dolayısıyla, görüntüleri önbelleğe almak için yapmanız gereken tek şey onları tarayıcıya yüklemek. Bir grup görüntüyü önbelleğe almak istiyorsanız, javascript'ten yapıldığında genellikle sayfa yüklemesini durdurmayacağı için muhtemelen en iyisi bunu javascript ile yapmaktır. Bunu şu şekilde yapabilirsiniz:

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"]);

Bu işlev istediğiniz kadar çağrılabilir ve her seferinde önbelleğe daha fazla görüntü ekler.

Resimler javascript aracılığıyla bu şekilde önceden yüklendikten sonra, tarayıcı bunları önbelleğinde tutar ve başka yerlerdeki (web sayfalarınızdaki) normal URL'lere başvurabilirsiniz ve tarayıcı bu URL'yi önbelleğinden alır. ağ.

Zamanla, tarayıcı önbelleği bir süredir kullanılmayan en eski şeyleri doldurabilir ve fırlatabilir. Sonuç olarak, görüntüler önbellekten temizlenir, ancak bir süre orada kalmaları gerekir (önbelleğin ne kadar büyük olduğuna ve diğer taramanın ne kadar yapıldığına bağlı olarak). Görüntüler her defasında yeniden önceden yüklendiğinde veya bir web sayfasında kullanıldığında, tarayıcı önbelleğindeki konumlarını otomatik olarak yeniler, böylece önbellekten çıkmaları daha az olasıdır.

Tarayıcı önbelleği sayfalar arasıdır, bu nedenle tarayıcıya yüklenen herhangi bir sayfa için çalışır. Böylece, sitenizde tek bir yerde önbelleğe alabilirsiniz ve ardından tarayıcı önbelleği sitenizdeki diğer tüm sayfalarda çalışacaktır.


Yukarıdaki gibi önden eklerken, resimler eşzamansız olarak yüklenir, böylece sayfanızın yüklenmesini veya görüntülenmesini engellemezler. Ancak, sayfanızın kendine ait çok sayıda görüntüsü varsa, bu önbellek görüntüleri bant genişliği veya sayfanızda görüntülenen görüntülerle bağlantılar için rekabet edebilir. Normalde, bu göze çarpan bir sorun değildir, ancak yavaş bir bağlantıda bu önleme, ana sayfanın yüklenmesini yavaşlatabilir. Önceden yüklenmiş görüntülerin en son yüklenmesi tamamsa, diğer tüm sayfa kaynakları zaten yüklenene kadar ön yüklemeyi başlatmak için bekleyecek bir işlev sürümü kullanabilirsiniz.

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

Bu örnekte, her url için yeni bir Image nesnesi oluşturuyorsunuz. Eğer döngü img değişken dışında ayarlanır ve sadece src güncellerseniz, aynı etkiyi ve kaynaklar kısmak gerekir
cadlac

2
@cadlac - Ancak tarayıcının her görüntüyü gerçekten indirip önbelleğe alacağından emin olmak için, yeni bir .src özelliği ayarlamadan önce bir görüntünün indirilmesinin bitmesini beklemeniz gerekir. Aksi takdirde, tarayıcı önceki indirmeyi durdurabilir ve asla başarılı bir şekilde önbelleğe alamaz.
jfriend00

Tarayıcıların daha yeni sürümlerinde beklemeden çalışıyor gibi görünüyor, ancak iyi bir noktaya değindiniz. Onun 'için uyumluluk :) görmek için bazı eski tarayıcılarda denemek gerekecek
cadlac

@cadlac - gerek yok. Image()Görüntünün yüklenmesi bittiğinde öğeyi listeden kaldırmak için kodu güncelledim . Görüntünün yüklenmesi bitene kadar beklemek daha güvenlidir.
jfriend00

1
Diğer belge kaynakları yüklenene kadar bekleyen komut dosyasının başka bir sürümünü ekledim, böylece görüntülerin önceden yüklenmesi, görünür sayfa kaynaklarının yüklenmesiyle bant genişliği için rekabet etmez.
jfriend00

13

@Pointy, görüntüleri javascript ile önbelleğe almadığınızı söylediği gibi, tarayıcı bunu yapıyor. yani bu sizin istediğiniz olabilir ve olmayabilir ... ama javascript kullanarak görüntüleri önceden yükleyebilirsiniz. Önceden yüklemek istediğiniz tüm görüntüleri bir diziye yerleştirerek ve bu dizideki tüm görüntüleri gizli img öğelerine koyarak, görüntüleri etkin bir şekilde önceden yüklersiniz (veya önbelleğe alırsınız).

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

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

2
bir görüntüyü bir sayfaya önceden yüklemek (görüntülemeden) ve ardından sonraki sayfada görüntülemek mümkün olabilir mi?
Logan Besecker

2
Bildiğim kadarıyla, bir sayfaya önceden yüklerseniz, tarayıcının önbelleğine girilecek ve ardından başka herhangi bir sayfada daha hızlı görüntülenecektir. Eğer bu yanlışsa, lütfen birisi düzeltsin
Trav McKinney

4

Sorunuzda "javascript kullanılıyor" prefetchyazsa da, herhangi bir varlığı önceden yüklemek için bir bağlantı etiketinin özniteliğini kullanabilirsiniz . Bu yazı itibariyle (10 Ağustos 2016), Safari'de desteklenmiyor, ancak hemen hemen her yerde destekleniyor:

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

Destekle ilgili daha fazla bilgiyi burada bulabilirsiniz: http://caniuse.com/#search=prefetch

IE 9,10'un caniusematriste listelenmediğini unutmayın, çünkü Microsoft bunlara yönelik desteği durdurmuştur.

Dolayısıyla, javascript kullanmaya gerçekten takıldıysanız, bu öğeleri sayfanıza dinamik olarak eklemek için jquery'yi de kullanabilirsiniz ;-)


1
Güzel güzel güzel güzel
Bhargav Nanekalva

3

Bakabileceğiniz birkaç şey var:

Görüntülerinizi önceden yükleme
.htaccess dosyasında önbellek süresi ayarlama Görüntülerin
dosya boyutu ve bunları kodlayan base64.

Ön yükleme: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

Önbelleğe alma: http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html

Base64 kodlaması için birkaç farklı düşünce var, bazıları http'nin bant genişliğini azalttığını söylerken, diğerleri "algılanan" yüklemenin daha iyi olduğunu söylüyor. Bunu havada bırakacağım.


3

Cevapların eksiksiz olması için ekleme: HTML ile önceden yükleme

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

Diğer önyükleme özellikleri mevcuttur, ancak hiçbiri şu amaca uygun değildir <link rel="preload">:

  • <link rel="prefetch">tarayıcılarda uzun süredir desteklenmektedir, ancak bir sonraki gezinme / sayfa yüklemesinde (örneğin bir sonraki sayfaya gittiğinizde) kullanılacak kaynakları önceden getirmek için tasarlanmıştır. Bu iyi, ancak mevcut sayfa için kullanışlı değil! Ek olarak, tarayıcılar önceden getirme kaynaklarına önceden yüklemeye göre daha düşük bir öncelik verir - mevcut sayfa bir sonrakinden daha önemlidir. Daha fazla ayrıntı için Bağlantıyı önceden getirme SSS bölümüne bakın .
  • <link rel="prerender">arka planda belirli bir web sayfasını oluşturur ve kullanıcı bu sayfaya giderse yüklemesini hızlandırır. Kullanıcıların bant genişliğini boşa harcama potansiyeli nedeniyle Chrome, önceden oluşturmayı bunun yerine bir NoState ön getirmesi olarak ele alır.
  • <link rel="subresource"> bir süre önce Chrome'da destekleniyordu ve önyüklemeyle aynı sorunu çözmeyi amaçlıyordu, ancak bir sorunu vardı: öğeler için bir öncelik belirlemenin bir yolu yoktu (o zamanlar mevcut olmadığı için) oldukça düşük bir öncelikle getirildi.

Dışarıda bir dizi komut dosyası tabanlı kaynak yükleyici vardır, ancak tarayıcının getirme önceliklendirme kuyruğu üzerinde herhangi bir güçleri yoktur ve hemen hemen aynı performans sorunlarına tabidirler.

Kaynak: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content


1

JS aracılığıyla eşzamansız önyükleme görüntüleri için benzer bir cevabım var . Bunları dinamik olarak yüklemek, normal şekilde yüklemekle aynıdır. önbelleğe alacaklar.

önbelleğe almaya gelince, tarayıcıyı kontrol edemezsiniz, ancak sunucu aracılığıyla ayarlayabilirsiniz. Talep üzerine gerçekten yeni bir kaynak yüklemeniz gerekiyorsa, yeni bir kaynağı yüklemeye zorlamak için önbellek bozma tekniğini kullanabilirsiniz.


1

Yavaş yükleme görüntüleri için benzer bir teknik kullanıyorum, ancak yardım edemiyorum, ancak Javascript'in ilk yüklemede tarayıcı önbelleğine erişmediğini fark ediyorum.

Örneğim:

Ana sayfamda 4 resimle dönen bir banner var, kaydırıcı 2 saniye bekliyor, javascript sonraki resmi yüklediğinde, 2 saniye bekler, vb.

Bu görüntülerin, her değiştirdiğimde değişen benzersiz url'leri var, bu nedenle tarayıcıda bir yıl boyunca önbelleğe alacak önbelleğe alma başlıkları alıyorlar.

max-age: 31536000, public

Şimdi Chrome Devtools'u açtığımda ve 'Önbelleği devre dışı bırak' seçeneğinin etkin olmadığından ve sayfayı ilk kez yüklediğimden (önbelleği temizledikten sonra) emin olduğumda, tüm resimler alınıyor ve 200 durumuna sahip. Başlıktaki tüm görüntülerin tam bir döngüsünden sonra ağ istekleri durur ve önbelleğe alınan görüntüler kullanılır.

Şimdi düzenli bir yenileme yaptığımda veya bir alt sayfaya gidip geri tıkladığımda, önbellekteki görüntüler göz ardı ediliyor gibi görünüyor. Chrome geliştiricilerinin Ağ sekmesinde "disk önbelleğinden" gri bir mesaj görmeyi bekliyorum. Bunun yerine isteklerin gri yerine Yeşil bir durum çemberiyle her iki saniyede bir geçtiğini görüyorum, verilerin aktarıldığını görüyorum, böylece javascript'ten önbelleğe hiç erişilmediği izlenimini alıyorum. Yalnızca sayfa her yüklendiğinde görüntüyü getirir.

Böylece ana sayfaya yapılan her istek, görüntünün önbelleğe alma politikasından bağımsız olarak 4 isteği tetikler.

Yukarıdakileri birlikte ve çoğu web sunucusu ve tarayıcının artık desteklediği yeni http2 standardını göz önünde bulundurursak, http2 tüm görüntüleri neredeyse aynı anda yükleyeceğinden, lazyloading kullanmayı bırakmanın daha iyi olacağını düşünüyorum.

Bu, Chrome Devtools'daki bir hataysa, bunu henüz kimsenin fark etmemesi gerçekten şaşırtıcı. ;)

Bu doğruysa, yavaş yükleme kullanmak yalnızca bant genişliği kullanımını artırır.

Yanılıyorsam lütfen beni düzeltin. :)


1

Günümüzde, görüntü oluşturma sürecinizi önbelleğe almak ve iyileştirmek için Google tarafından önerilen yeni bir teknik var :

  1. JavaScript Lazysizes dosyasını ekleyin: lazysizes.js
  2. Dosyayı, kullanmak istediğiniz html dosyasına ekleyin: <script src="lazysizes.min.js" async></script>
  3. Ekle lazyloadresminize sınıfı: <img data-src="images/flower3.png" class="lazyload" alt="">


0

Görüntüleri yüklemek için her zaman Konva JS: Görüntü Olayları'nda belirtilen örneği kullanmayı tercih ederim .

  1. Nesne veya dizi olarak görüntü URL'lerinin bir listesine sahip olmanız gerekir, örneğin:

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

  2. Görüntü URL'lerinin listesini ve argümanlar listesinde bir geri arama işlevini aldığı İşlev tanımını tanımlayın, böylece görüntüyü yüklemeyi bitirdiğinde web sayfanızda excution başlatabilirsiniz:

    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. Son olarak, işlevi çağırmanız gerekir. Sen örneğin diyebilirsiniz jQuerybireyin Belge Ready

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.