加载第三方 JS 的各种姿势

  虽然这对页面原有JS的执行不会有大的影响,但会影响到第三方JS代码本身的下载与执行。如何解决这个问题呢?

  你可能已经发现上面的例子有个问题:HTML代码中 g.js 的位置在 test.js 之后却先下载了。其实这得益于浏览器的预解析机制,会先对HTML代码做静态分析找到外链的JS和CSS文件,然后并行下载下来(但是执行顺序不变)。IE>=8 及其他主流浏览器基本都实现了这个功能。所以在这些支持预先载的浏览器中流程图应该是这样的:

物联网

  为了利用预加载这个特性,我们可以使用如下的写法:

  

  

  

  使用标准的 script 标签写法,确保浏览器能够正确的识别这是一个外链JS文件。同时设置 async 标签,浏览器便会异步加载 test.js 文件,不会暂停掉浏览器的解析执行。流程图如下:

物联网

  这里有一个 DEMO 。

  但它也并不完美,因为一些 旧浏览器 并不支持 async 属性。这会导致这个 test.js 文件在这些浏览器中不是异步的,并且会阻止掉页面渲染。有一个好消息是移动浏览器大多都支持 async 标签,如果你的用户大都是移动浏览器的,或者你的产品不支持旧浏览器,那么你可以使用这种方法。

  当然如果你不介意第三方JS代码(本身也支持支持)被延后到页面解析完毕后执行,那么你可以再加上 defer 属性:

  

  Firefox支持 defer 属性要比支持 async 早一点点。而且当浏览器同时使用了 async 和 defer 属性之后, 浏览器会忽略 defer 属性 。所以可以放心的同时使用 async 和 defer 属性。对于不支持 async 的浏览器,会自动fallback到 defer 。不过支持程度也就多了一点点,Firefox的旧版占比已经很低了,基本可以忽略不计。

  页面 alt="物联网" width="550" height="296" />

  可以看到因为 test.js 的下载速度变慢,整个页面一直处于loading状态。页面的 load 事件要等到全部加载完成之后才会触发。如果页面中的主要逻辑是在页面 load之后再执行,那么页面很可能会在很长一段时间内不可用。极大的影响了用户的使用体验。

  Friendly IFrame方法

  为了解决这个问题,meebo的工程师想了一个方案来解决这个问题:

  (function(url){

  // 第一部分

  var dom,doc,where,iframe = document.createElement('iframe');

  iframe.src = "javascript:false";

  iframe.title = ""; iframe.role="presentation";

  (iframe.frameElement || iframe).style.cssText = "width: 0; height: 0; border: 0";

  where = document.getElementsByTagName('script');

  where = where[where.length - 1];

  where.parentNode.insertBefore(iframe, where);

  // 第二部分

  try {

  doc = iframe.contentWindow.document;

  } catch(e) {

  // IE下如果主页面修改过document.domain,那么访问用js创建的匿名iframe会发生跨域问题,必须通过js伪协议修改iframe内部的domain

  dom = document.domain;

  iframe.src="javascript:var d=document.open();d.domain='"+dom+"';void(0);";

  doc = iframe.contentWindow.document;

  }

  doc.open()._l = function() {

  var js = this.createElement("script");

  if(dom) this.domain = dom;

  js.id = "js-iframe-async";

  js.src = http://www.netofthings.cn/JieJueFangAn/2016-10/url;

  this.body.appendChild(js);

  };

  doc.write('');

  doc.close();

  })('test.js');

  上述代码分为两个部分:

  创建了一个隐藏的 iframe 标签,设置其 src 值为JS代码,然后插入到主页面中

  在 iframe 标签load之后加载JS脚本

  这样加载Javascript,就不会阻止浏览器的>onload 事件比较动态创建 script 标签dynamic_script.html是否是(IE<=9除外)兼容性最好、普适性最高的方案