• 【JS】575- 动态插入的script脚本执行时间


    在一些场景我们会动态插入script标签加载js。

    譬如某个js文件不是很重要,并不是整个页面需要的脚本,可能只是某个功能需要的,这个功能可能是用户点击了某个按钮才触发,入口比较深。且和你页面本身的结构不同类,譬如你是基于react的页面,这个功能的js是jquery插件。这种js文件我一般采用动态加载方式引入。

    如果你用js动态插入script,那么它什么时候执行呢,如果插入多个script,且之间有依赖关系,是否先插入的script先执行呢?

    答案是:不是

    demo案例

    js-exec.js:动态插入2个script到页面中,test1.js中定义了一个全局变量objtest2.js加载完成后的onload事件中会去使用这个变量objtest1.jstest2.js都在打印了信息方便查看执行顺序

    var getReadyForEditor = () => {
      console.log(obj.foo)
    }
    
    var editorJs = document.createElement("script")
    editorJs.src = "./test1.js"
    document.body.appendChild(editorJs)
    
    var editorJs2 = document.createElement("script")
    editorJs2.src = "./test2.js"
    editorJs2.onload = getReadyForEditor
    document.body.appendChild(editorJs2) 
    

    test1.js: 控制台打印1,并且定义了obj变量

    console.log(1)
    var obj = {
      foo: 'foo'
    }
    

    test2.js: 控制台打印2。

    console.log(2)
    

    执行

    通过不断刷新,发现大概率是按照test1、test2的顺序执行,但是也有一部分是先执行test2再执行test1:

    由截图可见,网络请求顺序是按照script插入的顺序,先插入到dom的先请求,但是请求时间不一样,test2比test1的请求时间短,内容先返回。看现象貌似结论是:资源加载完成时执行,因此资源加载先完成的先执行

    猜测

    我们都知道如果是非动态插入的script,是按照在html里出现的顺序执行的,但是现在动态插入的脚本,虽然先插入的script位于html的前面,后插入的在后面,但是执行顺序却没有按这个顺序来。

    是不是因为浏览器不知道在一个script标签插入后还有没有下一个要插入,所以没法按顺序执行呢?那么我们一次性插入这2个标签会怎样?

    var getReadyForEditor = () => {
      console.log(obj.foo)
    }
    
    var editorJs = document.createElement("script")
    editorJs.src = "./test1.js"
    // document.body.appendChild(editorJs)
    
    var editorJs2 = document.createElement("script")
    editorJs2.src = "./test2.js"
    editorJs2.onload = getReadyForEditor
    // document.body.appendChild(editorJs2) 
    
    var docFrag = document.createDocumentFragment()
    docFrag.appendChild(editorJs) // Note that this does NOT go to the DOM
    docFrag.appendChild(editorJs2)
    document.body.appendChild(docFrag) 
    

    通过createDocumentFragment创造文档片段,然后一次插入,这样浏览器该知道顺序了吧。

    但是结果依旧没变。猜想错误!

    真相

    MDN文档:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script

    原来是因为浏览器对动态插入的script标签,默认设置的是async。(各浏览器有区别)

    我们知道async作用的js脚本时没有顺序的,异步加载,加载后执行。

    因此特性,所以还有个deferdefer是异步加载,按script在文档中的顺序执行。

    那我们的测试demo试一下,打印出来的async果真是true

    如何让动态插入的script标签按插入顺序执行

    既然问题出在async上,那么创建script标签时把他设置为false就好。

    var editorJs = document.createElement("script")
    editorJs.src = "./test1.js"
    editorJs.async = false
    document.body.appendChild(editorJs)
    
    var editorJs2 = document.createElement("script")
    editorJs2.src = "./test2.js"
    editorJs2.onload = getReadyForEditor
    editorJs2.async = false
    document.body.appendChild(editorJs2) 
    

    再观察,即使test2比test1先加载完,也会等待test1执行完在执行了~

    原创系列推荐

    1. JavaScript 重温系列(22篇全)

    2. ECMAScript 重温系列(10篇全)

    3. JavaScript设计模式 重温系列(9篇全)

    4. 正则 / 框架 / 算法等 重温系列(16篇全)

    5. Webpack4 入门(上)|| Webpack4 入门(下)

    6. MobX 入门(上) ||  MobX 入门(下)

    7. 59篇原创系列汇总

    回复“加群”与大佬们一起交流学习~

    点这,与大家一起分享本文吧~

    个人博客:http://www.pingan8787.com 微信公众号【前端自习课】和千万网友一起,每日清晨,享受一篇前端优秀文章。 目前已连续推送文章 600+ 天,愿每个人的初心都能一直坚持下去!
  • 相关阅读:
    基于java容器注解---基于泛型的自动装配
    mininet+floodlight搭建sdn环境并创建简单topo
    Bean装配之@Autowired注解
    Linux常用命令
    Bean利用Resource接口获取资源的几种方式
    MYSQL分页优化查询
    MYSQL统计和识别重复值
    MYSQL统计和识别重复值
    MYSQL处理数据重复值
    MYSQL处理数据重复值
  • 原文地址:https://www.cnblogs.com/pingan8787/p/13069400.html
Copyright © 2020-2023  润新知