Bunu nasıl yapacağınıza dair cevaplarda çok fazla değişiklik gördüm, bu yüzden onları burada özetleyeceğim (artı kendi icadımın 4. yöntemini ekleyeceğim):
(1) URL'ye benzersiz bir önbellek bozma sorgu parametresi ekleyin, örneğin:
newImage.src = "image.jpg?t=" + new Date().getTime();
Artıları: % 100 güvenilir, hızlı ve kolay anlaşılır ve uygulanabilir.
Eksileri: Önbelleği tamamen atlar, yani görüntüde gereksiz gecikmeler ve bant genişliği kullanımı vermez görünümler arasında değişir. Potansiyel olarak tarayıcı önbelleğini (ve herhangi bir ara önbelleği) tam olarak aynı görüntünün birçok kopyasını dolduracaktır! Ayrıca, resim URL'sinin değiştirilmesini gerektirir.
Ne zaman kullanılır: Canlı bir web kamerası feed'i gibi resim sürekli değişiyorsa kullanın. Bu yöntemi kullanırsanız , resimlerin kendileriyle birlikte sunulduğundan emin olun.Cache-control: no-cache
HTTP üstbilgileriyle sunduğunuzdan !!! (Genellikle bu bir .htaccess dosyası kullanılarak ayarlanabilir). Aksi takdirde önbellekleri görüntünün eski sürümleriyle aşamalı olarak dolduracaksınız!
(2) URL'ye yalnızca dosya yapıldığında değişen sorgu parametresi ekleyin, örneğin:
echo '<img src="image.jpg?m=' . filemtime('image.jpg') . '">';
(Bu PHP sunucu tarafı kodu, ama burada önemli olan sadece? M = [dosya son değiştirilme zamanı] sorgu dizesi eklenmesi).
Artıları: % 100 güvenilir, hızlı ve anlaşılması ve uygulanması kolay ve önbellekleme avantajlarını mükemmel şekilde korur.
Eksileri: Resim URL'sinin değiştirilmesini gerektirir. Ayrıca, sunucu için biraz daha çalışma - dosya son değiştirilme zamanına erişmek zorunda. Ayrıca, sunucu tarafı bilgileri gerektirir, bu nedenle yenilenmiş bir görüntü olup olmadığını kontrol etmek için yalnızca istemci tarafı çözümü için uygun değildir.
Ne zaman kullanılır: Görüntüleri önbelleğe almak istediğinizde, ancak dosya adını değiştirmeden zaman zaman sunucu sonunda güncellemeniz gerekebilir. VE HTML'nizdeki her resim örneğine doğru sorgu dizesinin eklenmesini kolayca sağlayabildiğinizde.
(3) Resimlerinizi üstbilgiyle sunun ve URL'ye Cache-control: max-age=0, must-revalidate
benzersiz bir memcache -şütücü parça tanımlayıcı ekleyin, örneğin:
newImage.src = "image.jpg#" + new Date().getTime();
Buradaki fikir, önbellek denetimi başlığının görüntüleri tarayıcı önbelleğine koyduğu, ancak hemen eskiyen olarak işaretlediği, böylece her yeniden görüntülendiğinde tarayıcının değiştirilip değiştirilmediğini görmek için sunucuyla kontrol etmesi gerekir. Bu, tarayıcının HTTP önbelleğinin her zaman görüntünün en son kopyasını döndürmesini sağlar. Bununla birlikte, tarayıcılar genellikle bir görüntünün bellek içi bir kopyasını varsa kullanırlar ve bu durumda HTTP önbelleklerini kontrol etmezler. Bunu önlemek için bir parça tanımlayıcısı kullanılır: Bellek içi görüntülerin karşılaştırılması src
parça tanımlayıcısını içerir, ancak HTTP önbelleğini sorgulamadan önce çıkarılır. (Yani, örneğin,image.jpg#A
ve image.jpg#B
ikisinden de görüntülenebilir image.jpg
girişin tarayıcı HTTP önbelleği, ancakimage.jpg#B
image.jpg#A
en son ne zamandan itibaren bellekte tutulan görüntü verileri kullanılarak görüntülenmez).
Artıları: HTTP önbellek mekanizmalarını doğru şekilde kullanır ve değişmediyse önbelleğe alınmış görüntüleri kullanır. Statik resim URL'sine eklenen bir sorgu dizesini tıkayan sunucular için çalışır (sunucular hiçbir zaman parça tanımlayıcılarını görmediğinden - yalnızca tarayıcıların kendi kullanımları içindir).
Eksileri: URL'lerinde parça tanımlayıcılarına sahip görüntülerle ilgili olarak, tarayıcıların biraz şüpheli (veya en azından kötü belgelenmiş) davranışına dayanır (Ancak, bunu başarıyla FF27, Chrome33 ve IE11'de test ettim). Her görüntü görünümü için yine de sunucuya bir yeniden doğrulama isteği gönderir; bu, görüntüler nadiren değişiyorsa ve / veya gecikme büyükse sorun teşkil eder (önbelleğe alınan görüntü hala iyi olsa bile yeniden doğrulama yanıtını beklemeniz gerektiğinden) . Resim URL'lerinin değiştirilmesini gerektirir.
Ne zaman kullanılır: Görüntülerin sık sık değişebileceği veya istemci tarafından sunucu tarafı komut dosyası katılımı olmadan, ancak önbelleğe almanın avantajını istediğiniz yerde zaman zaman yenilenmesi gerektiğinde kullanın. Örneğin, görüntüyü birkaç dakikada bir düzensiz güncelleyen canlı bir web kamerası çağırma. Alternatif olarak, sunucunuz statik resim URL'lerinde sorgu dizelerine izin vermiyorsa (1) veya (2) yerine kullanın.
(4) Zorla içine ilk yükleme bunun tarafından Javascript kullanarak belirli bir resme yenilemek gizli <iframe>
ve sonra çağıran location.reload(true)
iframe en üstünde contentWindow
.
Adımlar:
Yenilenecek resmi gizli bir iframe'e yükleyin. Bu sadece bir kurulum adımıdır - istenirse gerçek yenileme uzun zaman önce yapılabilir. Görüntünün bu aşamada yüklenememesi bile önemli değil!
Bu yapıldıktan sonra, o görüntünün sayfalarınızdaki veya herhangi bir DOM düğümündeki (javascript değişkenlerinde depolanan sayfa dışı olanlar bile) tüm kopyalarını boşaltın. Bu, tarayıcının görüntüyü eski bir bellek içi kopyadan görüntüleyebilmesi nedeniyle gereklidir (IE11 özellikle bunu yapar): HTTP önbelleğini yenilemeden önce tüm bellek içi kopyaların temizlendiğinden emin olmanız gerekir . Diğer javascript kodu eşzamansız olarak çalışıyorsa, bu kodun yenilenecek görüntünün yeni kopyalarını bu arada oluşturmasını da engellemeniz gerekebilir.
Arayın iframe.contentWindow.location.reload(true)
. true
Kuvvetler bir önbellek baypas, sunucudan doğrudan yeniden ve mevcut önbelleğe alınmış bir kopyasını üzerine yazarak.
Yeniden yükleme işlemi bittikten sonra , boş görüntüleri geri yükleyin. Şimdi sunucudan yeni sürümü görüntülemelidir!
Aynı etki alanı görüntüleri için, görüntüyü doğrudan iframe'e yükleyebilirsiniz. Alanlar arası resimler için bunun yerine , alan adınızdan bir <img>
etikette resim içeren bir HTML sayfası yüklemeniz gerekir , aksi takdirde aramaya çalıştığınızda "Erişim Reddedildi" hatası alırsınız iframe.contentWindow.reload(...)
.
Artıları: Tıpkı image.reload () işlevi gibi çalışır olmasını istediğiniz ! Görüntülerin normal olarak önbelleğe alınmasına izin verir (isterseniz son kullanma tarihlerinde bile, böylece sık sık yeniden doğrulama yapılmasını önler). Yalnızca istemci tarafı kodunu kullanarak geçerli sayfadaki veya diğer sayfalardaki URL'leri değiştirmeden belirli bir görüntüyü yenilemenize olanak tanır.
Eksileri: Javascript dayanır. Her tarayıcıda% 100 düzgün çalışması garanti edilmez (Bunu FF27, Chrome33 ve IE11'de başarıyla test ettim). Diğer yöntemlere göre çok karmaşık.
Ne zaman kullanılır: Önbelleğe alınmasını istediğiniz temelde statik resimlerden oluşan bir koleksiyona sahip olduğunuzda, ancak bunları arada sırada güncelleyebilmeniz ve güncellemenin gerçekleştiği anında görsel geri bildirim alabilmeniz gerekir. (Özellikle AJAX üzerine kurulmuş bazı web uygulamalarında olduğu gibi, tarayıcı sayfasının tamamını yenilerken çalışmaz). Ve (1) - (3) yöntemleri uygun olmadığında (ne olursa olsun), güncellemeniz gereken resmi gösterebilecek potansiyel URL'leri değiştiremezsiniz. (Bu 3 yöntemi kullanarak görüntünün yenileneceğini unutmayın, ancak başka bir sayfa bu görüntüyü uygun sorgu dizesi veya parça tanımlayıcısı olmadan görüntülemeye çalışırsa , bunun yerine eski bir sürüm gösterebilir).
Bunu bir peri sağlam ve esnek bir şekilde uygulamanın detayları aşağıda verilmiştir:
Web sitenizin URL yolunda boş bir 1x1 piksel .gif içerdiğini /img/1x1blank.gif
ve ayrıca aşağıdaki tek satırlı PHP komut dosyasına sahip olduğunu varsayalım (yalnızca etki alanları arası görüntülere zorunlu yenileme uygulamak için gereklidir ve herhangi bir sunucu tarafı komut dosyası dilinde yeniden yazılabilir) , elbette) URL yolunda /echoimg.php
:
<img src="<?=htmlspecialchars(@$_GET['src'],ENT_COMPAT|ENT_HTML5,'UTF-8')?>">
Ardından, tüm bunları Javascript'te nasıl yapabileceğinizin gerçekçi bir uygulaması. Biraz karmaşık görünüyor, ancak çok fazla yorum var ve önemli işlev sadece forceImgReload () - ilk ikisi sadece boş ve boş olmayan görüntüler ve kendi HTML'nizle verimli çalışacak şekilde tasarlanmalıdır, bu yüzden bunları kodlayın sizin için en iyi şekilde çalışır; bunlardaki komplikasyonların çoğu web siteniz için gereksiz olabilir:
// This function should blank all images that have a matching src, by changing their src property to /img/1x1blank.gif.
// ##### You should code the actual contents of this function according to your page design, and what images there are on them!!! #####
// Optionally it may return an array (or other collection or data structure) of those images affected.
// This can be used by imgReloadRestore() to restore them later, if that's an efficient way of doing it (otherwise, you don't need to return anything).
// NOTE that the src argument here is just passed on from forceImgReload(), and MAY be a relative URI;
// However, be aware that if you're reading the src property of an <img> DOM object, you'll always get back a fully-qualified URI,
// even if the src attribute was a relative one in the original HTML. So watch out if trying to compare the two!
// NOTE that if your page design makes it more efficient to obtain (say) an image id or list of ids (of identical images) *first*, and only then get the image src,
// you can pass this id or list data to forceImgReload() along with (or instead of) a src argument: just add an extra or replacement parameter for this information to
// this function, to imgReloadRestore(), to forceImgReload(), and to the anonymous function returned by forceImgReload() (and make it overwrite the earlier parameter variable from forceImgReload() if truthy), as appropriate.
function imgReloadBlank(src)
{
// ##### Everything here is provisional on the way the pages are designed, and what images they contain; what follows is for example purposes only!
// ##### For really simple pages containing just a single image that's always the one being refreshed, this function could be as simple as just the one line:
// ##### document.getElementById("myImage").src = "/img/1x1blank.gif";
var blankList = [],
fullSrc = /* Fully qualified (absolute) src - i.e. prepend protocol, server/domain, and path if not present in src */,
imgs, img, i;
for each (/* window accessible from this one, i.e. this window, and child frames/iframes, the parent window, anything opened via window.open(), and anything recursively reachable from there */)
{
// get list of matching images:
imgs = theWindow.document.body.getElementsByTagName("img");
for (i = imgs.length; i--;) if ((img = imgs[i]).src===fullSrc) // could instead use body.querySelectorAll(), to check both tag name and src attribute, which would probably be more efficient, where supported
{
img.src = "/img/1x1blank.gif"; // blank them
blankList.push(img); // optionally, save list of blanked images to make restoring easy later on
}
}
for each (/* img DOM node held only by javascript, for example in any image-caching script */) if (img.src===fullSrc)
{
img.src = "/img/1x1blank.gif"; // do the same as for on-page images!
blankList.push(img);
}
// ##### If necessary, do something here that tells all accessible windows not to create any *new* images with src===fullSrc, until further notice,
// ##### (or perhaps to create them initially blank instead and add them to blankList).
// ##### For example, you might have (say) a global object window.top.blankedSrces as a propery of your topmost window, initially set = {}. Then you could do:
// #####
// ##### var bs = window.top.blankedSrces;
// ##### if (bs.hasOwnProperty(src)) bs[src]++; else bs[src] = 1;
// #####
// ##### And before creating a new image using javascript, you'd first ensure that (blankedSrces.hasOwnProperty(src)) was false...
// ##### Note that incrementing a counter here rather than just setting a flag allows for the possibility that multiple forced-reloads of the same image are underway at once, or are overlapping.
return blankList; // optional - only if using blankList for restoring back the blanked images! This just gets passed in to imgReloadRestore(), it isn't used otherwise.
}
// This function restores all blanked images, that were blanked out by imgReloadBlank(src) for the matching src argument.
// ##### You should code the actual contents of this function according to your page design, and what images there are on them, as well as how/if images are dimensioned, etc!!! #####
function imgReloadRestore(src,blankList,imgDim,loadError);
{
// ##### Everything here is provisional on the way the pages are designed, and what images they contain; what follows is for example purposes only!
// ##### For really simple pages containing just a single image that's always the one being refreshed, this function could be as simple as just the one line:
// ##### document.getElementById("myImage").src = src;
// ##### if in imgReloadBlank() you did something to tell all accessible windows not to create any *new* images with src===fullSrc until further notice, retract that setting now!
// ##### For example, if you used the global object window.top.blankedSrces as described there, then you could do:
// #####
// ##### var bs = window.top.blankedSrces;
// ##### if (bs.hasOwnProperty(src)&&--bs[src]) return; else delete bs[src]; // return here means don't restore until ALL forced reloads complete.
var i, img, width = imgDim&&imgDim[0], height = imgDim&&imgDim[1];
if (width) width += "px";
if (height) height += "px";
if (loadError) {/* If you want, do something about an image that couldn't load, e.g: src = "/img/brokenImg.jpg"; or alert("Couldn't refresh image from server!"); */}
// If you saved & returned blankList in imgReloadBlank(), you can just use this to restore:
for (i = blankList.length; i--;)
{
(img = blankList[i]).src = src;
if (width) img.style.width = width;
if (height) img.style.height = height;
}
}
// Force an image to be reloaded from the server, bypassing/refreshing the cache.
// due to limitations of the browser API, this actually requires TWO load attempts - an initial load into a hidden iframe, and then a call to iframe.contentWindow.location.reload(true);
// If image is from a different domain (i.e. cross-domain restrictions are in effect, you must set isCrossDomain = true, or the script will crash!
// imgDim is a 2-element array containing the image x and y dimensions, or it may be omitted or null; it can be used to set a new image size at the same time the image is updated, if applicable.
// if "twostage" is true, the first load will occur immediately, and the return value will be a function
// that takes a boolean parameter (true to proceed with the 2nd load (including the blank-and-reload procedure), false to cancel) and an optional updated imgDim.
// This allows you to do the first load early... for example during an upload (to the server) of the image you want to (then) refresh.
function forceImgReload(src, isCrossDomain, imgDim, twostage)
{
var blankList, step = 0, // step: 0 - started initial load, 1 - wait before proceeding (twostage mode only), 2 - started forced reload, 3 - cancelled
iframe = window.document.createElement("iframe"), // Hidden iframe, in which to perform the load+reload.
loadCallback = function(e) // Callback function, called after iframe load+reload completes (or fails).
{ // Will be called TWICE unless twostage-mode process is cancelled. (Once after load, once after reload).
if (!step) // initial load just completed. Note that it doesn't actually matter if this load succeeded or not!
{
if (twostage) step = 1; // wait for twostage-mode proceed or cancel; don't do anything else just yet
else { step = 2; blankList = imgReloadBlank(src); iframe.contentWindow.location.reload(true); } // initiate forced-reload
}
else if (step===2) // forced re-load is done
{
imgReloadRestore(src,blankList,imgDim,(e||window.event).type==="error"); // last parameter checks whether loadCallback was called from the "load" or the "error" event.
if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
}
}
iframe.style.display = "none";
window.parent.document.body.appendChild(iframe); // NOTE: if this is done AFTER setting src, Firefox MAY fail to fire the load event!
iframe.addEventListener("load",loadCallback,false);
iframe.addEventListener("error",loadCallback,false);
iframe.src = (isCrossDomain ? "/echoimg.php?src="+encodeURIComponent(src) : src); // If src is cross-domain, script will crash unless we embed the image in a same-domain html page (using server-side script)!!!
return (twostage
? function(proceed,dim)
{
if (!twostage) return;
twostage = false;
if (proceed)
{
imgDim = (dim||imgDim); // overwrite imgDim passed in to forceImgReload() - just in case you know the correct img dimensions now, but didn't when forceImgReload() was called.
if (step===1) { step = 2; blankList = imgReloadBlank(src); iframe.contentWindow.location.reload(true); }
}
else
{
step = 3;
if (iframe.contentWindow.stop) iframe.contentWindow.stop();
if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
}
}
: null);
}
Ardından, sayfanızla aynı alanda bulunan bir görüntünün yenilenmesini zorlamak için şunları yapabilirsiniz:
forceImgReload("myimage.jpg");
Görüntüyü başka bir yerden yenilemek için (web alanları arası):
forceImgReload("http://someother.server.com/someimage.jpg", true);
Daha gelişmiş bir uygulama, sunucunuza yeni bir sürüm yükledikten sonra görüntüyü yeniden yüklemek ve kullanıcıya yeniden yükleme gecikmesini en aza indirmek için yeniden yükleme işleminin başlangıç aşamasını yükleme ile aynı anda hazırlamak olabilir. AJAX üzerinden yükleme yapıyorsanız ve sunucu çok basit bir JSON dizisi [başarı, genişlik, yükseklik] döndürüyorsa, kodunuz şöyle görünebilir:
// fileForm is a reference to the form that has a the <input typ="file"> on it, for uploading.
// serverURL is the url at which the uploaded image will be accessible from, once uploaded.
// The response from uploadImageToServer.php is a JSON array [success, width, height]. (A boolean and two ints).
function uploadAndRefreshCache(fileForm, serverURL)
{
var xhr = new XMLHttpRequest(),
proceedWithImageRefresh = forceImgReload(serverURL, false, null, true);
xhr.addEventListener("load", function(){ var arr = JSON.parse(xhr.responseText); if (!(arr&&arr[0])) { proceedWithImageRefresh(false); doSomethingOnUploadFailure(...); } else { proceedWithImageRefresh(true,[arr[1],ar[2]]); doSomethingOnUploadSuccess(...); }});
xhr.addEventListener("error", function(){ proceedWithImageRefresh(false); doSomethingOnUploadError(...); });
xhr.addEventListener("abort", function(){ proceedWithImageRefresh(false); doSomethingOnUploadAborted(...); });
// add additional event listener(s) to track upload progress for graphical progress bar, etc...
xhr.open("post","uploadImageToServer.php");
xhr.send(new FormData(fileForm));
}
Son bir not: Bu konu görüntülerle ilgili olmasına rağmen, potansiyel olarak diğer dosya veya kaynaklar için de geçerlidir. Örneğin, eski komut dosyası veya css dosyalarının kullanılmasının önlenmesi veya belki de güncellenmiş PDF belgelerinin yenilenmesi (yalnızca tarayıcıda açılacak şekilde ayarlanmışsa (4) kullanılarak). Yöntem (4), bu gibi durumlarda yukarıdaki javascript üzerinde bazı değişiklikler yapılmasını gerektirebilir.