这段时间在做一个广告系统,需要用js自动生成广告代码,其中遇到一些问题,在这记录下。
第三方广告代码一般都是用 document.write()向页面写入,这次使用的时候遇到不少坑,经常会出现使用document.write()向页面写入的时候当前页面被清空。这正是document.write()的特殊之处,页面载入后浏览器输出流自动关闭,此后对当前页面进行document.write()操作将打开—个新的输出流,它将清除当前页面内容(包括源文档的任何变量或值)。
那么有哪些浏览器输出流关闭的标识呢?我们首先想到的是 window.onload,在window.onload后页面加载完成,浏览器输出流必然关闭。经测试$(document).ready()中的操 作也是在浏览器输出流关闭之后执行。所以用于生成代码的document.write()不能写在window.onload 和$(document).ready()中。除了这两个之外有没有其他坑呢?js生成广告代码中需要ajax获取服务端的数据,ajax请求成功之后再 document.write()写入仍然会发生覆盖。这是因为jquery的ajax默认是异步请求,并不阻塞文档流,当ajax请求成功之后在执行操 作,浏览器输出流很可能就关闭了。这种情况可以把ajax默认请求改成同步,阻塞文档流,防止document.write()覆盖。
由于第三方广告代码使用document.write()输出,所有的广告资源都在页面载入时加载,如果页面上第三方广告比较多,必然会阻塞页面加载。有 没有办法在使用document.write()的情况下不阻塞页面加载呢?其实是可以的,这里就需要我们改造原生的document.write()方 法,在广告加载完毕再把原生方法改回来。这里就不具体展开来写,雨夜带刀博客
《让document.write的广告无阻塞的加载》
有详细分析,这里贴一下带刀改造document.write()的代码。
1 /**
2 * 重写document.write实现无阻塞加载script
3 * @param { Dom Object } textarea元素
4 */
5 var loadScript = function( elem ){
6 var url = elem.value.match( /src="([\s\S]*?)"/i )[1],
7 parent = elem.parentNode,
8 // 缓存原生的document.write
9 docWrite = document.write,
10 // 创建一个新script来加载
11 script = document.createElement( 'script' ),
12 head = document.head ||
13 document.getElementsByTagName( 'head' )[0] ||
14 document.documentElement;
16 // 重写document.write
17 document.write = function( text ){
18 parent.innerHTML = text;
19 };
21 script.type = 'text/javascript';
22 script.src = url;
24 script.onerror =
25 script.onload =
26 script.onreadystatechange = function( e ){
27 e = e || window.event;
28 if( !script.readyState ||
29 /loaded|complete/.test(script.readyState) ||
30 e === 'error'
31 ){
33 // 恢复原生的document.write
34 document.write = docWrite;
35 head.removeChild( script );
37 // 卸载事件和断开DOM的引用
38 // 尽量避免内存泄漏
39 head =
40 parent =
41 elem =
42 script =
43 script.onerror =
44 script.onload =
45 script.onreadystatechange = null;
47 }
48 }
50 // 加载script
51 head.insertBefore( script, head.firstChild );
52 };