34

默认情况下 $.getScript() 禁用缓存,您可以使用 $.ajaxSetup 并将缓存设置为 true。在测试脚本是否实际使用 Firebug 缓存时,大多数情况下脚本返回 200(这意味着脚本是新副本),可能有 20 或 30 次返回 304(意味着它使用了缓存版本)。为什么它在绝大多数时间都得到一个新副本?

$.ajaxSetup({
    cache: true
 });

 $.getScript( scriptFile );

getScript 检索的文件尚未被编辑,请求是分开的页面更改。

4

6 回答 6

31

首先让我们澄清一下 jQuery 禁用缓存是什么意思。

当 jQuery禁用缓存时,意味着浏览器会通过某种技巧强制文件再次加载,例如在 url 末尾添加一个额外的随机数作为参数。

当 jQuery启用缓存时,不会强制执行任何操作,而是让您在此文件的标题上设置的缓存。这意味着如果您没有设置文件头参数以将其保留在浏览器缓存中,浏览器将尝试通过某些方法再次加载它。

因此,通过 jQuery 启用缓存,您还必须在静态文件上设置正确的缓存标头以保留在浏览器缓存中,否则浏览器可能会尝试再次加载它们。

对于浏览器在标题上看到创建日期的文件,然后连接到服务器再次询问标题,比较它,如果没有更改,则不再加载它,而是向服务器发出一次调用。

对于您设置了最大年龄的文件,并且在该日期之前不询问服务器,如果他找到它,浏览器会直接从缓存中加载它。

总结一下:让浏览器
根据cache:true您发送的标头决定是否缓存此文件。
cache:false是强制文件再次加载。

一些与缓存相关的问题:
缓存 JavaScript 文件
IIS7 Cache-Control

里面
的代码getScript()调用jQuery.get()女巫是Ajax的简写函数

$.ajax({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});

因此,通过调用getScript()您进行 ajax 调用,如果这是您最初的想法,那么 jQuery 不会保留任何类型的文件缓存。

加载 sripts 的自定义函数
如果您没有创建全局缓存:true,并且您只需要使用缓存:true 加载一些文件,则可以将自定义函数设置为:

function getScriptCcd(url, callback)
{
    jQuery.ajax({
            type: "GET",
            url: url,
            success: callback,
            dataType: "script",
            cache: true
    });
};

这不受全局缓存参数的影响,加载脚本文件时不添加任何非缓存参数。

于 2012-10-14T19:08:24.117 回答
11

自发布此问题之日起出现错误,Firefox 和 Chrome 都会声明脚本没有从缓存中加载,而实际上它确实是。截至本答案发布之日,此问题仍然存在。最简单的测试方法是使用 console.log 并发送一个版本号。

要缓存动态加载的脚本,只需使用以下代码即可完成。

function onDemandScript ( url, callback ) {
    callback = (typeof callback != 'undefined') ? callback : {};

    $.ajax({
         type: "GET",
         url: url,
         success: callback,
         dataType: "script",
         cache: true
     });    
}

对于开发,您应该注释掉 cache: true。

于 2013-05-13T01:57:09.847 回答
4

默认情况下,$.getScript() 将缓存设置为 false。这会将时间戳查询参数附加到请求 URL,以确保浏览器在每次请求时下载脚本。

jQuery doc 站点有一个很好的扩展,可以不向请求附加时间戳并绕过缓存:

jQuery.cachedScript = function( url, options ) {

  // Allow user to set any option except for dataType, cache, and url
  options = $.extend( options || {}, {
    dataType: "script",
    cache: true,
    url: url
  });


  // Use $.ajax() since it is more flexible than $.getScript
  // Return the jqXHR object so we can chain callbacks
  return jQuery.ajax( options );
};

// Usage
$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
  console.log( textStatus );
});

来源

于 2016-01-14T07:21:25.367 回答
4

实际上有一个更好的选择,您可以为某些请求打开缓存,例如:

$.ajaxPrefilter(function( options ) {
  if ( options.type==='GET' && options.dataType ==='script' ) {
      options.cache=true;
  }
});
于 2017-03-08T19:39:30.253 回答
2

我知道这是一篇旧帖子,现有的答案是真正的答案,但谈到 Iscariot 的担忧,它真的是在缓存(至少有点像)。这只是firefox的一个怪癖。也许这对那些被这个怪癖弄糊涂的其他人证明是有用的。

我用一个非常大的 javascript 文件测试了这个概念,该文件根据数万个纬度的数组定义了爱达荷州 DOT 区边界的谷歌地图多边形(未压缩的文件大小为 2,806,257,但我通过压缩过程运行它)。使用以下 javascript

// Grab polys if not already loaded
if (typeof(defaults.data.polys) === 'undefined') {
    /*$.getScript('/Scripts/ScriptMaster.php?file=Districts', function () {});*/
    $.ajax({
        type: "GET",
        url: '/Scripts/ScriptMaster.php?file=Districts',
        success: function() {
            defaults.data.polys = getPolys();
            data.polys = defaults.data.polys;
        },
        dataType: "script",
        cache: true
    });
}

你可以看到相关的 php(你不希望实际的 Districts.js 文件在这篇文章中占用太多空间,所以这里是 ScriptMaster.php)

<?php
require_once('../settings.php');

if (!isset($_GET['file'])) die();
$file = $_GET['file'];
$doCache = $file == 'Districts';

header('Content-type: application/x-javascript');
if ($doCache) {
    // This is a luxury for loading Districts.js into cache to improve speed
    //  It is at the top because firefox still checks the server for
    //  headers even when it's already cached
    $expires = 7 * 60 * 60 * 24; // set cache control to expire in a week (this is not likely to change)
    header('Cache-Control: max-age='.$expires.', must-revalidate');
    header('Last-modified: Fri, 3 May 2013 10:12:37 GMT');
    header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expires).'GMT');
    header('Pragma: public');
}

ob_start("compress");
require_once($file.".js");
ob_end_flush();

function compress($buffer) {
    global $doCache;
    if (DEV_MODE && !$doCache) return $buffer;
    /* remove comments */
        $buffer = preg_replace('/\/\/.+?$/m', '', preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer));
    /* remove tabs, spaces, new lines, etc. */
        $buffer = str_replace(array("\r\n", "\r", "\n", "\t", '  ', '    ', '    '), '', $buffer);
    /* remove unnecessary spaces */
        $buffer = str_replace(': ', ':', $buffer);
        $buffer = str_replace(' :', ':', $buffer);
        $buffer = str_replace(', ', ',', $buffer);
        $buffer = str_replace(' ,', ',', $buffer);
        $buffer = str_replace('; ', ';', $buffer);
        $buffer = str_replace(' ;', ';', $buffer);
        $buffer = str_replace('{ ', '{', $buffer);
        $buffer = str_replace(' {', '{', $buffer);
        $buffer = str_replace('} ', '}', $buffer);
        $buffer = str_replace(' }', '}', $buffer);

    if ($doCache) { header('Content-Length: '.strlen($buffer)); }

    return $buffer;
}
?>

重要的是要注意,在脚本之前调用 php 的标头函数甚至会执行您要打印的字符串,这与 chrome 不同,并且可能(可能,我懒得检查)其他浏览器 firefox 似乎会对服务器进行 ping在使用缓存之前检查标头。也许通过更多的研究,您可以确定这是否与 ajax 中的元素一样(可能不是)。

所以我做了五次测试运行,显示了这个脚本的加载时间,如 firebug 中所述。这是结果

#results loading the script after clearing cache (yes those are seconds, not ms)
200 OK      4.89s
200 OK      4.9s
200 OK      5.11s
200 OK      5.78s
200 OK      5.14s

#results loading the page with control+r
200 OK      101ms
200 OK      214ms
200 OK      24ms
200 OK      196ms
200 OK      99ms
200 OK      109ms

#results loading the page again by navigating (not refreshing)
200 OK      18ms
200 OK      222ms
200 OK      117ms
200 OK      204ms
200 OK      19ms
200 OK      20ms

如您所见,我的 localhost 服务器到 Web 客户端的连接不是最一致的,而且我的笔记本电脑规格有点破旧(单核处理器等等,它也有几年历史了)但重点是负载显着下降缓存加载后的时间。

[此外,如果有人对没有压缩脚本感到好奇(不像制表符、空格或新行被浪费,它必须仍然可读)需要 7-8 秒才能加载,但我不会这样做 5次]

所以不要害怕,它真的是缓存。老实说,对于只需要 ms 加载的较小脚本,您可能不会注意到 firefox 的差异;仅仅因为它检查来自服务器的标头。我之所以知道这一点,是因为从将这些标头函数从脚本末尾移动到开头的加载时间发生了变化。如果您在 php 遍历字符串之后拥有这些函数,则加载时间会更长。

希望这可以帮助!

于 2013-05-11T05:10:14.553 回答
0

您可能正在寻找的是一个getScriptOnce函数,基本上,如果它知道文件已经成功加载,则在调用此类函数时不会再次加载此类文件。

我写了这样的功能。您可以使用Firebug 或 Chrome 开发工具中的网络选项卡进行测试。这只会加载同一个文件一次。您只需要将getScriptOnce函数和全局数组复制到您的文件中ScriptArray

var getScriptOnce = (function(url, callback) {
  var scriptArray = []; //array of urls
  return function (url, callback) {
      //the array doesn't have such url
      if (scriptArray.indexOf(url) === -1){
          if (typeof callback === 'function') {
              return $.getScript(url, function(script, textStatus, jqXHR) {
                  scriptArray.push(url);
                  callback(script, textStatus, jqXHR);
              });
          } else {
              return $.getScript(url, function(){
                  scriptArray.push(url);
              });
          }
      }
      //the file is already there, it does nothing
      //to support as of jQuery 1.5 methods .done().fail()
      else{
          return {
              done: function () {
                  return {
                      fail: function () {}
                  };
              }
          };
      }
  }
}());

/*#####################################################################*/
/*#####################################################################*/


//TEST - tries to load the same jQuery file twice
var jQueryURL = "https://code.jquery.com/jquery-3.2.1.js";
console.log("Tries to load #1");
getScriptOnce(jQueryURL, function(){
  console.log("Loaded successfully #1")
});

//waits 2 seconds and tries to load again
window.setTimeout(function(){
  console.log("Tries to load #2");
  getScriptOnce(jQueryURL, function(){
    console.log("Loaded successfully #2");
  });
}, 2000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

于 2017-08-10T19:21:52.107 回答