Is there another way to disable cache when fetching script? - javascript

I use this to fetch script;
$.getScript("http://www.example.org/");
However, I dont want it to be cached. Means that if I use getScript again, the script should fetch it again.
This one works in theory;
$.getScript("http://www.example.org/?" + Math.random());
But in practically, it's not. Because the "?" is disabled on the remote site url, so my question is, is there any otherway to tell browser to not cache ?

Recreate the function for your needs:
(function () {
$.getScript = function(url, callback) {
$.ajax({
type: "GET",
url: url,
success: callback,
dataType: "script",
cache: false
});
};
})();
Now it won't cache anymore when you call the function like
$.getScript('script.js', function()
{
// non cached script.js
});

The remote site cannot disable the effectiveness of "http://www.example.org/?" + Math.random() to prevent caching.
The point of the "?" + Math.random() is to create a unique URL that will not be in the local browser cache. It is the local browser that makes this caching decision and, for local browser caching, it does not matter if the remote site is ignoring the "?" + Math.random() part of the URL or not.
FYI, another way to address caching is for your server to return proper cache headers when this script is retrieved that instruct the browser to never cache this file.

Related

Force a page reload (not from cache) and keep scroll position? [duplicate]

How can I force the web browser to do a hard refresh of the page via JavaScript?
Hard refresh means getting a fresh copy of the page AND refresh all the external resources (images, JavaScript, CSS, etc.).
⚠️ This solution won't work on all browsers. MDN page for location.reload():
Note: Firefox supports a non-standard forceGet boolean parameter for location.reload(), to tell Firefox to bypass its cache and force-reload the current document. However, in all other browsers, any parameter you specify in a location.reload() call will be ignored and have no effect of any kind.
Try:
location.reload(true);
When this method receives a true value as argument, it will cause the page to always be reloaded from the server. If it is false or not specified, the browser may reload the page from its cache.
More info:
The location object
window.location.href = window.location.href
Accepted answer above no longer does anything except just a normal reloading on mostly new version of web browsers today. I've tried on my recently updated Chrome all those, including location.reload(true), location.href = location.href, and <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />. None of them worked.
My solution is by using server-side capability to append non-repeating query string to all included source files reference as like below example.
<script src="script.js?t=<?=time();?>"></script>
So you also need to control it dynamically when to keep previous file and when to update it. The only issue is when files inclusion is performed via script by plugins you have no control to modify it. Don't worry about source files flooding. When older file is unlinked it will be automatically garbage collected.
Changing the current URL with a search parameter will cause browsers to pass that same parameter to the server, which in other words, forces a refresh.
(No guarantees if you use intercept with a Service Worker though.)
const url = new URL(window.location.href);
url.searchParams.set('reloadTime', Date.now().toString());
window.location.href = url.toString();
If you want support older browsers:
if ('URL' in window) {
const url = new URL(window.location.href);
url.searchParams.set('reloadTime', Date.now().toString());
window.location.href = url.toString();
} else {
window.location.href = window.location.origin
+ window.location.pathname
+ window.location.search
+ (window.location.search ? '&' : '?')
+ 'reloadTime='
+ Date.now().toString()
+ window.location.hash;
}
That said, forcing all your CSS and JS to refresh is a bit more laborious. You would want to do the same process of adding a searchParam for all the src attributes in <script> and href in <link>. That said it won't unload the current JS, but would work fine for CSS.
document.querySelectorAll('link').forEach((link) => link.href = addTimestamp(link.href));
I won't bother with a JS sample since it'll likely just cause problems.
You can save this hassle by adding a timestamp as a search param in your JS and CSS links when compiling the HTML.
This is a 2022 update with 2 methods, considering SPA's with # in url:
METHOD 1:
As mentioned in other answers one solution would be to put a random parameter to query string. In javascript it could be achieved with this:
function urlWithRndQueryParam(url, paramName) {
const ulrArr = url.split('#');
const urlQry = ulrArr[0].split('?');
const usp = new URLSearchParams(urlQry[1] || '');
usp.set(paramName || '_z', `${Date.now()}`);
urlQry[1] = usp.toString();
ulrArr[0] = urlQry.join('?');
return ulrArr.join('#');
}
function handleHardReload(url) {
window.location.href = urlWithRndQueryParam(url);
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
The bad part is that it changes the current url and sometimes, in clean url's, it could seem little bit ugly for users.
METHOD 2:
Taking the idea from https://splunktool.com/force-a-reload-of-page-in-chrome-using-javascript-no-cache, the process could be to get the url without cache first and then reload the page:
async function handleHardReload(url) {
await fetch(url, {
headers: {
Pragma: 'no-cache',
Expires: '-1',
'Cache-Control': 'no-cache',
},
});
window.location.href = url;
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
Could be even combined with method 1, but I think that with headers should be enought:
async function handleHardReload(url) {
const newUrl = urlWithRndQueryParam(url);
await fetch(newUrl, {
headers: {
Pragma: 'no-cache',
Expires: '-1',
'Cache-Control': 'no-cache',
},
});
window.location.href = url;
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
UPDATED to refresh all the external resources (images, JavaScript, CSS, etc.)
Put this in file named HardRefresh.js:
function hardRefresh() {
const t = parseInt(Date.now() / 10000); //10s tics
const x = localStorage.getItem("t");
localStorage.setItem("t", t);
if (x != t) location.reload(true) //force page refresh from server
else { //refreshed from server within 10s
const a = document.querySelectorAll("a, link, script, img")
var n = a.length
while(n--) {
var tag = a[n]
var url = new URL(tag.href || tag.src);
url.searchParams.set('r', t.toString());
tag.href = url.toString(); //a, link, ...
tag.src = tag.href; //rerun script, refresh img
}
}
}
window.addEventListener("DOMContentLoaded", hardRefresh);
window.addEventListener("deviceorientation", hardRefresh, true);
This code do a fully controled forced hard refresh for every visitor, so that any update will show up without a cashing problem.
Duplicated DOM rendering is not a performance issue, because the first render is from cache and it stops rendering in <script src="js/HardRefresh.js"> where it reload a page from server. When it run a refreshed page it also refresh urls in page.
The last refresh time x is stored in localStorage. It is compared with the current time t to refresh within 10 seconds. Assuming a load from server not take more than 10 sec we manage to stop a page refresh loop, so do not have it less than 10s.
For a visitor of page the x != t is true since long time ago or first visit; that will get page from server. Then diff is less than 10s and x == t, that will make the else part add query strings to href and src having sources to refresh.
The refresh() function can be called by a button or other conditioned ways. Full control is managed by refining exclusion and inclusion of urls in your code.
For angular users and as found here, you can do the following:
<form [action]="myAppURL" method="POST" #refreshForm></form>
import { Component, OnInit, ViewChild } from '#angular/core';
#Component({
// ...
})
export class FooComponent {
#ViewChild('refreshForm', { static: false }) refreshForm;
forceReload() {
this.refreshForm.nativeElement.submit();
}
}
The reason why it worked was explained on this website: https://www.xspdf.com/resolution/52192666.html
You'll also find how the hard reload works for every framework and more in this article
explanation: Angular
Location: reload(), The Location.reload() method reloads the current URL, like the Refresh button. Using only location.reload(); is not a solution if you want to perform a force-reload (as done with e.g. Ctrl + F5) in order to reload all resources from the server and not from the browser cache. The solution to this issue is, to execute a POST request to the current location as this always makes the browser to reload everything.
The most reliable way I've found is to use a chache buster by adding a value to the querystring.
Here's a generic routine that I use:
function reloadUrl() {
// cache busting: Reliable but modifies URL
var queryParams = new URLSearchParams(window.location.search);
queryParams.set("lr", new Date().getTime());
var query = queryParams.toString();
window.location.search = query; // navigates
}
Calling this will produce something like this:
https://somesite.com/page?lr=1665958485293
after a reload.
This works to force reload every time, but the caveat is that the URL changes. In most applications this won't matter, but if the server relies on specific parameters this can cause potential side effects.

Urls that don't finish with / won't load properly other embebed pages

Has anyone encountered this problem?
I have been working with c# MVC in Visual Studio and when we publish our pages if the user tries to access the page and doesn't end the URL with / some pages won't load properly.
We use a lot that we have a main page and then somewhere in the middle is a div that is updated through javascript (I know that's what the render from mvc does when using the layout, but our boss doesn't like it that way and also it tends to interfere with her multiple layers of javascript)
It is these div parts that are loaded this way that won't load when the main page doesn't have a / at the end.
we have tried using #url.action and also hard typing the URL of the second page in the javascript and both yield the same result.
Is there a way to configure the project so that it doesn't matter whether the url that was typed in the browser has the / at the end?
EDIT: Added javascript function
function refreshdiv(divid, url) {
var seconds = 15;
$.ajax({
type: 'POST',
url: url,
context: document.body,
async: true,
timeout: 15000,
success: function (data) {
$("#" + divid).html(data);
$("#" + divid).find("script").each(function (i) {
eval($(this).text());
});
}
});
Thanks in Advance for any help

Save plugin loaded with Ajax to cache

So I'm using this code to change the content of my website and loading specific plugins for each "page":
$.ajax({
url: urlPath,
type: 'GET',
success: loadContent //content and plugins are loaded through this
});
Now I noticed it doesn't cache the loaded plugins from loadContent, each time downloading them again and again, thefore the page using ajax requests is 0.5s to 1.5s slower than simple http requests (obviously after the plugins have already been cached from first load).
Using cache: true/false doesn't make any difference.
I've read this can't be done, because javascript can't write to disk, but still maybe I missed something and there is a way to cache the plugins and avoid losing additional time on each load?
You can use an alternative to cache which is localStorage. Each website has the right to store up to 5 MB of data on the user disk.
So use this to save data:
//browser support localStorage
if((typeof(Storage) !== "undefined"){
localStorage.setItem("mydataname", data);
}
And to retrieve or download a new one:
//browser support localStorage
if((typeof(Storage) !== "undefined"){
var data = localStorage.getItem("mydataname");
if(data){ //data does exist in localStorage
// Use data, no need to download a new version.
}
else{ // data doesn't exist, not saved yet or have been removed
// download new version of data and save it using the above code.
}
}
else{
// browser doesn't support localStorage redownload data.
}
More about localStorage here.

Loading gif not working in IE & Chrome

I have been searching and have found some similar questions about this problem but thing still doesn't work for me at all.
Here is my function :
function ajaxRequest(url, type, datatype, contenttype, data, displayLoadingImg){
var result="";
displayLoadingImg = (typeof displayLoadingImg === "undefined") ? 0 : displayLoadingImg;
if(displayLoadingImg == 1){
$("#loadingImgAging").css("display","block");
}
$.ajax({
url:url,
type:type,
dataType:datatype,
contentType: contenttype,
data : JSON.stringify(data),
success:function(res){
result = res;
if(displayLoadingImg == 1){
$("#loadingImgAging").css("display","none");
}
},
error:function(res){
result="";
},
async : false
});
return result;
}
How I call it :
setTimeout(ajaxRequest(url,"GET","json","application/json",0,1), 500);
I've tried using beforeSend() but it did not work neither.
Note : If I delete async : false or put it to true, I'll get error Cross-Origin Request Blocked.... in my browser console.
My guess is you cannot do an ajax request with local files. There are ways to do this, but i prefer these two methods
Create a simple server
I usually use python for creating a simple server. Type this in your terminal/console: "python -m SimpleHTTPServer 9081" (or any port number you want to). Then, just open your localhost referring to your specified port.
Open chrome in --allow-file-access-from-files mode
or create a batch file using this following code in Windows. Chrome must be restarted before the configuration takes place.
start "chrome" "C:\Program Files (x86)\Google\Chrome\Application\chrome" --allow-file- access-from-files
exit
I assume you are making a AJAX call to another domain file for which you have to use JSONP as your dataType. Doing this you then dont have to make async = false.
Try this:
before you do the ajax call set display to block, after the ajax call(success or error doesnt matter) - just before you return - set display to none. You dont need displayLoadingImg and the code to handle it. Or do I miss ssomething?

Safari caching my AJAX request

I want one of my pages to fire a javascript AJAX call every time the user loads the page, even if he is coming back to a page in the browser's history. So I've put this function in my jsp (I am using jQuery Mobile):
$(document).on(
"pageinit",
"#base-layout",
function() {
$.ajaxSetup({ cache: false });
myFunction(urlEndpoint);
});
With only this code, and the javascript function:
function myFunction(url) {
var currentTime = new Date();
var n = currentTime.getTime();
var epUrl = url + "?nocache" + n;
$.ajax({
url : epUrl,
dataType: "json",
method: "post",
headers : { "cache-control": "no-cache" },
cache:false,
}).done(function(data) {
//do something
});
}
I managed to get Chrome, Firefox and IE to actually fire the ajax call even when pressing the back button. But I can't manage to get Safari to show this behavior. No matter what I try, it's never going through my server side function.
As you can see, I tried disabling cache for the ajax call, and changing the endpoint url by appendind the current time, to no effect. I even tried to put
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
on my controller method, but it didn't work either. I can't get Safari to call this function when coming back to a page in history.

Categories

Resources