前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【JS】575- 动态插入的script脚本执行时间

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

作者头像
pingan8787
发布2020-04-26 14:15:49
2.7K0
发布2020-04-26 14:15:49
举报
文章被收录于专栏:前端自习课前端自习课

在一些场景我们会动态插入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都在打印了信息方便查看执行顺序

代码语言:javascript
复制
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变量

代码语言:javascript
复制
console.log(1)
var obj = {
  foo: 'foo'
}

test2.js: 控制台打印2。

代码语言:javascript
复制
console.log(2)

执行

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

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

猜测

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

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

代码语言:javascript
复制
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就好。

代码语言:javascript
复制
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执行完在执行了~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端自习课 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • demo案例
  • 执行
  • 猜测
  • 真相
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档