मैंने यह करने के लिए उत्तरों में बहुत भिन्नता देखी है, इसलिए मैंने सोचा कि मैं उन्हें यहाँ संक्षेप में बताऊंगा (साथ ही अपने स्वयं के आविष्कार का एक चौथा तरीका भी जोड़ूँगा):
(1) URL में एक अद्वितीय कैश-बस्टिंग क्वेरी पैरामीटर जोड़ें, जैसे:
newImage.src = "image.jpg?t=" + new Date().getTime();
पेशेवरों: 100% विश्वसनीय, त्वरित और समझने और लागू करने में आसान।
विपक्ष: पूरी तरह से कैशिंग को बायपास करता है , जब भी विचारों के बीच छवि नहीं बदलती है तो अनावश्यक देरी और बैंडविड्थ का उपयोग होता है । संभावित रूप से एक ही छवि के कई, कई प्रतियों के साथ ब्राउज़र कैश (और किसी भी मध्यवर्ती कैश) को भर देगा! इसके अलावा, छवि URL को संशोधित करने की आवश्यकता है।
कब इस्तेमाल करें: जब इमेज लगातार बदल रही हो, जैसे लाइव वेबकैम फीड के लिए इस्तेमाल करें। यदि आप इस विधि का उपयोग करते हैं, तो Cache-control: no-cache
HTTP हेडर के साथ चित्रों को स्वयं परोसना सुनिश्चित करें !!! (अक्सर इसे .htaccess फ़ाइल का उपयोग करके सेट किया जा सकता है)। अन्यथा आप उत्तरोत्तर छवि के पुराने संस्करणों के साथ कैश भरना होगा!
(2) URL में क्वेरी पैरामीटर जोड़ें जो केवल फ़ाइल में परिवर्तन करता है, जैसे:
echo '<img src="image.jpg?m=' . filemtime('image.jpg') . '">';
(यह PHP सर्वर-साइड कोड है, लेकिन यहां महत्वपूर्ण बिंदु सिर्फ इतना है कि एक? M = [अंतिम बार संशोधित फ़ाइल] querystring फ़ाइल नाम में जोड़ा गया है)।
पेशेवरों: 100% विश्वसनीय, त्वरित और समझने और लागू करने में आसान, और कैशिंग लाभ को पूरी तरह से संरक्षित करता है।
विपक्ष: छवि URL को संशोधित करने की आवश्यकता है। इसके अलावा, सर्वर के लिए थोड़ा और काम - इसे फ़ाइल-अंतिम-संशोधित समय तक पहुंच प्राप्त करना होगा। इसके अलावा, सर्वर-साइड जानकारी की आवश्यकता होती है, इसलिए एक ताज़ा छवि के लिए जाँच करने के लिए केवल शुद्ध क्लाइंट-साइड समाधान के लिए उपयुक्त नहीं है।
कब उपयोग करें: जब आप छवियों को कैश करना चाहते हैं, लेकिन फ़ाइल नाम को बदले बिना उन्हें समय-समय पर सर्वर अंत में अपडेट करने की आवश्यकता हो सकती है। और जब आप आसानी से यह सुनिश्चित कर सकते हैं कि आपके HTML में हर छवि उदाहरण में सही querystring जोड़ा गया है।
(3) हेडर के साथ अपने चित्रों को परोसें Cache-control: max-age=0, must-revalidate
, और एक अद्वितीय जोड़ने मेम्कैश जैसे यूआरएल के लिए -busting टुकड़ा पहचानकर्ता,:
newImage.src = "image.jpg#" + new Date().getTime();
यहां विचार यह है कि कैश-कंट्रोल हेडर ब्राउज़र कैश में छवियां डालता है, लेकिन तुरंत उन्हें बासी चिह्नित करता है, ताकि और हर बार जब वे फिर से प्रदर्शित हों तो ब्राउज़र को सर्वर से जांचना होगा कि क्या उन्होंने बदल दिया है। यह सुनिश्चित करता है कि ब्राउज़र का HTTP कैश हमेशा छवि की नवीनतम प्रति लौटाता है। हालांकि, ब्राउज़र अक्सर एक छवि की इन-मेमोरी कॉपी का फिर से उपयोग करेंगे यदि उनके पास एक है, और उस मामले में अपने HTTP कैश की जांच भी नहीं करते हैं। इसे रोकने के लिए, एक टुकड़ा पहचानकर्ता का उपयोग किया जाता है: इन-मेमोरी छवि की तुलना में src
टुकड़े पहचानकर्ता शामिल है, लेकिन यह HTTP कैश को क्वेरी करने से पहले छीन लिया जाता है। (इसलिए, उदाहरण के लिए, image.jpg#A
और image.jpg#B
दोनों को प्रदर्शितimage.jpg
ब्राउज़र के HTTP कैश में प्रविष्टि है, लेकिनimage.jpg#B
image.jpg#A
अंतिम बार प्रदर्शित होने पर इन-मेमोरी मेमोरी इमेज डेटा का उपयोग करके कभी भी प्रदर्शित नहीं किया जाएगा )।
पेशेवरों: HTTP कैशिंग तंत्रों का उचित उपयोग करता है, और यदि वे नहीं बदले हैं तो कैश्ड चित्रों का उपयोग करते हैं। सर्वरों के लिए काम करता है जो एक स्थिर छवि URL में जोड़ा जाता है (क्योंकि सर्वर कभी भी टुकड़े के पहचानकर्ता नहीं देखते हैं - वे केवल ब्राउज़र के स्वयं के उपयोग के लिए हैं)।
विपक्ष: अपने URL में टुकड़े पहचानकर्ताओं के साथ छवियों के संबंध में, कुछ हद तक संदिग्ध (या कम से कम खराब दस्तावेज वाले) व्यवहार पर निर्भर करता है (हालाँकि, मैंने FF27, Chrome33 और IE11 में इसका सफलतापूर्वक परीक्षण किया है)। अब भी हर छवि को देखने के लिए सर्वर पर एक पुनर्विचार अनुरोध भेजते हैं, जो ओवरकिल हो सकता है यदि छवियां केवल शायद ही कभी बदलती हैं और / या विलंबता एक बड़ा मुद्दा है (क्योंकि आपको कैश्ड छवि अभी भी अच्छी है, तब भी आप अमान्य प्रतिक्रिया की प्रतीक्षा करने की आवश्यकता है) । छवि URL संशोधित करने की आवश्यकता है।
कब उपयोग करें: जब छवियाँ बार-बार बदल सकती हैं, या सर्वर-साइड स्क्रिप्ट की भागीदारी के बिना क्लाइंट द्वारा रुक-रुक कर ताज़ा करने की आवश्यकता होती है, लेकिन जहाँ आप अभी भी कैशिंग का लाभ चाहते हैं। उदाहरण के लिए, एक लाइव वेबकैम को मतदान करना जो हर कुछ मिनटों में अनियमित रूप से एक छवि को अपडेट करता है। वैकल्पिक रूप से, (1) या (2) के बजाय का उपयोग करें यदि आपका सर्वर स्थिर छवि URL पर querystrings की अनुमति नहीं देता है।
(4) किसी विशेष छवि को जबरन जावास्क्रिप्ट का उपयोग करके ताज़ा करें, पहले उसे एक छिपे हुए में लोड करके <iframe>
और फिर location.reload(true)
आईफ्रेम पर कॉल करके contentWindow
।
कदम हैं:
एक छिपे हुए आइफ्रेम में ताज़ा होने के लिए छवि को लोड करें। यह सिर्फ एक सेटअप कदम है - अगर वांछित है, तो यह वास्तविक रिफ्रेश से बहुत पहले किया जा सकता है। इससे कोई फर्क नहीं पड़ता कि छवि इस स्तर पर लोड करने में विफल रहती है!
एक बार ऐसा हो जाने के बाद, उस छवि की सभी प्रतियाँ अपने पेज पर या कहीं भी किसी भी डीओएम नोड्स (यहां तक कि जावास्क्रिप्ट चर में संग्रहीत ऑफ-पेज वाले) को खाली कर दें। यह आवश्यक है क्योंकि ब्राउज़र अन्यथा एक बासी-इन-मेमोरी कॉपी (विशेष रूप से ऐसा करता है) से छवि प्रदर्शित कर सकता है: HTTP कैश को रीफ्रेश करने से पहले आपको यह सुनिश्चित करने की आवश्यकता है कि सभी इन-मेमोरी प्रतियां साफ हो जाएं। यदि अन्य जावास्क्रिप्ट कोड एसिंक्रोनस रूप से चल रहा है, तो आपको उस कोड को बीच-बीच में ताज़ा करने वाली छवि की नई प्रतियां बनाने से भी रोकना पड़ सकता है।
पुकारते हैं iframe.contentWindow.location.reload(true)
। true
बलों एक कैश बाईपास, सर्वर से सीधे पुन: लोड और मौजूदा कैश्ड प्रतिलिपि को अधिलेखित।
एक बार जब यह फिर से लोड हो रहा है, तो खाली छवियों को पुनर्स्थापित करें। उन्हें अब सर्वर से ताज़ा संस्करण प्रदर्शित करना चाहिए!
समान-डोमेन छवियों के लिए, आप छवि को सीधे iframe में लोड कर सकते हैं। क्रॉस-डोमेन छवियों के लिए, आपको अपने डोमेन से एक HTML पृष्ठ लोड करना होगा जिसमें एक <img>
टैग में छवि शामिल है , अन्यथा आपको कॉल करने का प्रयास करते समय "एक्सेस अस्वीकृत" त्रुटि मिलेगी iframe.contentWindow.reload(...)
।
पेशेवरों: बस image.reload () फ़ंक्शन की तरह काम करता है जो आप चाहते हैं कि DOM था! छवियों को सामान्य रूप से कैश करने की अनुमति देता है (यहां तक कि भविष्य में समाप्ति तिथियों के साथ भी यदि आप उन्हें चाहते हैं, तो इस प्रकार बार-बार अमान्य होने से बचें)। आपको केवल क्लाइंट-साइड कोड का उपयोग करके वर्तमान पृष्ठ पर, या किसी अन्य पेज पर उस छवि के लिए यूआरएल को बदलने के बिना एक विशेष छवि को ताज़ा करने की अनुमति देता है।
विपक्ष: जावास्क्रिप्ट पर निर्भर करता है। प्रत्येक ब्राउज़र में ठीक से काम करने की गारंटी नहीं 100% (मैंने FF27, Chrome33 और IE11 में सफलतापूर्वक इसका परीक्षण किया है)। अन्य विधियों के सापेक्ष बहुत जटिल।
कब उपयोग करें: जब आपके पास मूल रूप से स्थिर छवियों का एक संग्रह होता है, जिसे आप कैश किया जाना चाहते हैं, लेकिन आपको अभी भी कभी-कभी उन्हें अपडेट करने और तत्काल दृश्य प्रतिक्रिया प्राप्त करने में सक्षम होने की आवश्यकता होती है, जो अपडेट हुआ था। (खासकर जब सिर्फ पूरे ब्राउज़र पृष्ठ को ताज़ा करने से काम नहीं चलेगा, जैसा कि उदाहरण के लिए AJAX में निर्मित कुछ वेब ऐप में है)। और जब विधियाँ (1) - (3) संभव नहीं हैं क्योंकि (जो भी कारण से) आप उन सभी URL को नहीं बदल सकते जो संभवतः आपके द्वारा अपडेट की गई छवि को प्रदर्शित कर सकते हैं। (ध्यान दें कि उन 3 विधियों का उपयोग करके छवि को ताज़ा किया जाएगा, लेकिन यदि कोई अन्य पृष्ठ फिर उस चित्र को उपयुक्त क्वेरिस्ट्रिंग या विखंडन पहचानकर्ता के बिना प्रदर्शित करने का प्रयास करता है , तो वह इसके बजाय एक पुराना संस्करण दिखा सकता है)।
एक परी मजबूत और लचीले तरीके से इसे लागू करने का विवरण नीचे दिया गया है:
मान लें कि आपकी वेबसाइट में URL पथ पर एक रिक्त 1x1 पिक्सेल .gif है /img/1x1blank.gif
, और इसमें निम्न एक-लाइन PHP स्क्रिप्ट भी है (केवल क्रॉस-डोमेन छवियों के लिए मजबूर ताज़ा लागू करने के लिए आवश्यक है , और किसी भी सर्वर-साइड स्क्रिप्टिंग भाषा में फिर से लिखा जा सकता है बेशक) URL पथ पर /echoimg.php
:
<img src="<?=htmlspecialchars(@$_GET['src'],ENT_COMPAT|ENT_HTML5,'UTF-8')?>">
फिर, यहाँ जावास्क्रिप्ट में आप यह सब कैसे कर सकते हैं, इसका यथार्थवादी कार्यान्वयन है। यह थोड़ा जटिल लग रहा है, लेकिन बहुत सारी टिप्पणियां हैं, और महत्वपूर्ण कार्य केवल बल ImgReload () है - पहले दो सिर्फ खाली और बिना-खाली चित्र, और आपके अपने HTML के साथ कुशलता से काम करने के लिए डिज़ाइन किया जाना चाहिए, इसलिए उन्हें कोड करें आपके लिए सबसे अच्छा काम करता है; उनमें से अधिकांश जटिलताएं आपकी वेबसाइट के लिए अनावश्यक हो सकती हैं:
// 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);
}
फिर, अपने पृष्ठ के समान डोमेन पर स्थित छवि को ताज़ा करने के लिए, आप बस कर सकते हैं:
forceImgReload("myimage.jpg");
कहीं और (क्रॉस-डोमेन) से एक छवि को ताज़ा करने के लिए:
forceImgReload("http://someother.server.com/someimage.jpg", true);
आपके सर्वर पर एक नया संस्करण अपलोड करने के बाद एक और अधिक उन्नत एप्लिकेशन को फिर से लोड करना पड़ सकता है, अपलोड के साथ-साथ रीलोड प्रक्रिया के प्रारंभिक चरण को तैयार करना, उपयोगकर्ता को दृश्यमान लोड देरी को कम करने के लिए। यदि आप AJAX के माध्यम से अपलोड कर रहे हैं, और सर्वर एक बहुत ही सरल JSON सरणी [सफलता, चौड़ाई, ऊंचाई] लौटा रहा है, तो आपका कोड कुछ इस तरह दिखाई दे सकता है:
// 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));
}
एक अंतिम नोट: हालाँकि यह विषय छवियों के बारे में है, यह संभावित रूप से अन्य प्रकार की फ़ाइलों या संसाधनों पर भी लागू होता है। उदाहरण के लिए, बासी स्क्रिप्ट या सीएसएस फ़ाइलों के उपयोग को रोकना, या शायद अपडेट किए गए पीडीएफ दस्तावेजों को भी ताज़ा करना (केवल ब्राउज़र में खोलने के लिए सेट होने पर (4) का उपयोग करना)। विधि (4) को इन मामलों में उपरोक्त जावास्क्रिप्ट में कुछ बदलावों की आवश्यकता हो सकती है।