提醒:本页面将不再更新、维护或者支持,文章、评论所叙述内容存在时效性,涉及技术细节或者软件使用方面不保证能够完全有效可操作,请谨慎参考!

这个是制作主题时遇到的,因为引用了JQuery脚本库,为了最佳的浏览体验,当然希望这个脚本库加载得越快越好,或者我们的主机商限制了流量,JQuery几十K的流量也要勒紧裤带啊,所以我们会考虑CDN,国内外流行的JQuery CDN有Google的或者Sina云计划,地址分别是:

http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js

然后我们就可以直接用script标签引用了,比如这样:

<script type="text/javascript"
        src="http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js">
</script>

好吧,速度问题算是解决了,而且有这些大公司做后盾,我们也不必考虑其他问题,等等,没有其他问题了吗?假如我说假如我使用的这家公司倒闭了呢?好吧,现阶段不可能无缘无故倒闭的;假如链接地址更改了呢?或者被XX了?好吧,这个是我们要考虑的问题,针对XX问题,我们可以选择国内sina的CDN,对于前一个问题,我们就需要考虑容灾措施了,假如这些发生了,我们该怎么做?

我现在博客的流量监控使用的是Google Analytics,发现其采用了如下这么段异步加载的措施:

try {
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXX-X']);
  _gaq.push(['_trackPageview']);

  (function() {
  var ga = document.createElement('script');
  ga.type = 'text/javascript';
  ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www')
       + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(ga, s);
  })();
}catch(e){}

进一步研究发现通过createElement('script')方法还可以获取其他特性,比如判断脚本是否已经加载完成,这个貌似对于刚才的问题有所帮助哎,于是我改写了这么一段代码:

(function( window, undefined ) {
  window.jQuery || (function(){
    var mirrors = [
      "lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js",
      location.hostname + "/blog/wp-includes/js/jquery/jquery.js"
    ];
    for (var i=0; i<mirrors.length; i++) {
      if(typeof(window.jQuery) == "undefined") {
        var script = document.createElement('script');
        script.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + mirrors[i];
        script.type = 'text/javascript';
        script.language = 'javascript';
        script.async = false;
        script.onload = script.onreadystatechange = function() {
          if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') {
            // 这里放依赖JQuery执行的代码
            script.onload = script.onreadystatechange = null;
          }
        }
        // document.body.appendChild(script); 这句换下面两句
         var s = document.getElementsByTagName('script')[0];
         s.parentNode.insertBefore(script, s);
      } else {
        break;
      }
    }
  })();
})(window);

想法倒是很好,思路就是通过查询mirrors列表先加载CDN的JQuery库,然后通过typeof(window.jQuery)判断是否加载成功,如果不成功则继续加载mirrors剩下的地址指向的JQuery库,我这里直接写上本地WordPress自带的JQuery库地址。但是实际操作中发现问题多多,主要是异步加载,我也尝试着将async设置为false,但是仍然异步加载脚本,这样导致每次循环typeof(window.jQuery)==undefined,这样导致mirrors里面的库全部被加载了,试了很多次,无果, 遂放弃了这个办法

我后来搜索了一下,又 找到了一个办法 ,那就是通过下面的代码来实现加载:

<script type='text/javascript' src='http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js'></script>
<script type="text/javascript">
//<![CDATA[
if (typeof jQuery == 'undefined') {
  document.write(unescape("%3Cscript src='/blog/wp-includes/js/jquery/jquery.js' type='text/javascript'%3E%3C/script%3E")); 
}
// ]]>
</script>

也就是说一般加载选择script标签引入CDN地址,如果加载失败也就是typeof jQuery为undefined,那就输出script,并引入本地JQuery库。我用FireBug观察了一下,发现这种方式是阻塞加载,也就是同步的,就不存在刚才遇到的问题了。

对于WordPress可以通过在functions.php里面修改或者加入下面的代码来实现嵌入JQuery库。

function my_init() {
    if (!is_admin()) {
        wp_deregister_script('jquery');
        wp_register_script('jquery',("http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js"), false, "1.7.2", false);
        wp_enqueue_script('jquery');
    }
}
add_action('init', 'my_init');

这样head标签里就嵌入了script外链的SinaApp JQuery库,为了能快速渲染页面,有些同学喜欢将其加入页面底部,其实只需要将wp_register_script改成下面这样既可:

wp_register_script('jquery',("http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js"), false, "1.7.2", true);

注意最后一个参数,为true时代表将引用JQuery的script标签嵌入页面底部,如果需要加入额外的判断代码,比如刚才的判断JQuery加载失败就引入本地库的那段可以先建立函数my_jquery_reload:

function my_jquery_reload() {
 // 这里输出代码
}

如果加入头部(head)则使用下面的代码:

add_action('wp_head', 'my_jquery_reload');

如果加入底部则使用下面的代码:

add_action('wp_footer', 'my_jquery_reload');

好了,我的介绍完了。