JavaScript的异步加载

js的异步加载

JavaScript是单线程执行,即代码会一行一行自上而下执行,正常来讲,浏览器是同步加载js代码的,但是一旦遇到网速不好,或者加载的js代码文件过大,容易造成页面阻塞,整个网站将等待js加载而不进行后续的渲染工作,影响交互体验。

如:HTML元素按照其页面出现顺序渲染,此时js获取DOM对象,若DOM结构还没有加载完成,就会获取到空对象。


    
    
    
    Document
    



    

    这是因为js是一行一行代码执行,js加载执行在DOM结构之前,故为null。解决:通常把

    ②async异步加载

    特点:加载完就执行,async只能加载外部脚本,不能把js写在script标签里面

    
    

    ③动态创建script标签

    //tools.js
    function test()
    {    
        console.log('hello world')
    }
    
    //在页面中引入tools.js,并执行里面的方法
    
    

     当程序执行至 test() 时,前面的 script.src="tools.js" 还没加载完毕。解决:

    ①设置在1秒之后执行,即等js下载完后再执行

    
    

     ②监听是否加载完毕

    // 兼容性好,但不适用于ie
    
    
    // 适用于ie
    

    兼容性写法:

    
        
    

    报错原因:页面用到 test()时, script.src 还没有加载。解决:将 test,js 写成对象形式

    //tools.js
    // function test() {
    //     console.log('hello world')
    // }
    const tools = {
        test: function() {
            console.log('hello world')
        }
    }
    
    
    
        
    

    有时候为了将DOM文档解析完之后执行js代码,便将js写在DOM文档结构之后,但是这样写不够美观。解决:监听页面是否加载完成

    window.addEventListener('load',function(){.....});   
    // 1、页面所有的东西加载并且执行完之后才执行的方法,假如页面其中任何一个src的资源没被加载,该onload事件便无法执行。运行效率慢
    
    document.addEventListener('DOMContentLoaded',function(){.....},false); 
    // 2、当纯 HTML 被完全加载以及解析时,事件会被触发,而不必等待样式表,图片或者子框架完成加载。 效率较高

    在你的脚本有机会运行前,DOMContentLoaded可能就已经被触发。所以在决定添加一个事件监听器前最好先检查一下。只能用addEventListener来监听时间是否触发

    function doSomething() {
      console.info('DOM loaded');
    }
    
    if (document.readyState === 'loading') {  // 此时加载尚未完成
      document.addEventListener('DOMContentLoaded', doSomething);
    } else {  // 此时`DOMContentLoaded` 已经被触发
      doSomething();
    }

     

    了解js加载时间线

    浏览器在开始运行一个页面时,会初始化js功能,当js开始作用时,记录了一系列浏览器按照顺序做的事情,也就是一个执行顺序。

    js时间线:

    1、创建Document对象,开始解析web页面,解析HTML元素和文本内容后,添加Element对象和Text节点到文档中,这个节点document.readyState="loading"

    2、遇到 link 外部 css,创建线程,进行异步加载,并继续解析文档。

    3、遇到 script 外部 js,并且没有设置 async、defer,浏览器同步加载,并阻塞,等待 js 加载完成并执行该脚本,然后继续解析文档。

    4、遇到 script 外部 js,并且设置有 async、defer,浏览器创建线程异步加载,并继续解析文档。(异步禁止使用 document.write())

    注意:
    1、async 属性的脚本,脚本加载完成后立即执行。defer属性脚本要等到dom解析完成后再执行。

    2、异步禁止使用 document.write():因为整个文档解析到差不多,再调用document.write(),会把之前所有的文档流都清空,用它里面的文档代替。除了异步禁止,而且当内容全部加载完毕后也要禁止使用document.write(),也就是window.onload。

    5、遇到 img 等(带有 src),先正常解析 dom 结构,然后浏览器异步加载 src,并继续解析文档。看到标签直接生产 dom 树,不用等着 img 加载完 src。

    6、当文档解析完成(domTree 建立完毕,不是加载完毕,解析在加载之前),document.readyState = 'interactive'。

    7、文档解析完成后,所有设置有 defer 的脚本会按照顺序执行。(注意与 async 的不同,但同样禁止使用 document.write());

    8、文档解析完成后,document 对象触发 DOMContentLoaded 事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段。

    9、当所有 async 的脚本加载完成并执行后、img 等加载完成后(页面所有的都执行加载完之后),document.readyState = 'complete',window 对象触发 load 事件。

    10、从此,以异步响应方式处理用户输入、网络事件等。

    你可能感兴趣的:(前端,javascript,前端,html)