Table of Content

如标题所说,不受控制的 JS,主要是说在别人服务器上的,尤其是被 GFW 的,当然了,不只限于 JS 文件,CSS,图片什么的都可以,原理大同小异。

我的博客上面的资源,几乎所有的 JS,图片,都在自己的 CDN,其他的在 VPS,只有 Google Analytics 和 Disqus 引用的第三方 JS。

事情需要从这个博客的 Theme,Namjagbarwa 说起,首页的 card 在 layout 之前,需要保证所有外部资源加载完毕,其代码类似于这样:

$(window).load(function() {

  window.sr = window.ScrollReveal().reveal(cardName, {
      afterReveal: function () {
          if ($postsGrid) {
              $postsGrid.masonry("layout");
          }
      }
  });
});

没加载完的时候是一片空白。界面上什么都没有,造成一种假死的状态。

如果想加入 Disqus 评论个数的功能,需要引入 count.js,所以就导致了没翻墙的情况下,这个资源根本无法加载成功,阻塞了 $(window).load()

即时这个 script 标签设置 async=true,也是会阻塞。

解决办法很巧妙,既然 $(window).load() 只会在所有资源加载完毕的时候触发,那太简单了,把 Disqus 干掉不就好了么。。当然不行,干掉了还怎么显示评论个数。

JS 对资源的判定标准是,Tag 里面有 src Attribute,我们只需要把这个 Attribute 干掉,就能保证 $(window).load() 忽略掉这个 JS。

<script type="text/javascript">  
    (function () {
        var s = document.createElement('script'); s.async = true;
        s.type = 'text/javascript';
        s.setAttribute('external_src', '//' + window.disqus_shortname + '.disqus.com/count.js');
        (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
    }());
</script>  

我们把 count.js 的 Attribute 设置为 external_src,就不会再阻塞 rendering,但是资源也没法加载了咋弄,这就更容易了,在 load 之后遍历一下:

$(window).load(function() {
    $('[external_src]').each(function() {
        var external_src = $(this).attr("external_src");
        $(this).attr("src", $(this).attr("external_src")).removeAttr("external_src");
    });
});

这样就完美解决了。