1. script指定src后内部代码无效
<script src='/test.js'>
console.log(222) // 不会执行
</script>
<script src='/test.js'></script>
<script>
console.log(222) // 可以执行
</script>
2. async 和 defer
async与defer的区别:
defer和async都是让script异步加载,但是:
- defer能够保证script加载的顺序,并且defer会在domContentLoaded事情之前执行defer中的代码;
- asyn不能够保证script加载顺序,并且加载完后就会立即执行,不能保证在DomContentLoaded之前或者之后执行。
2.1 defer
- defer不会阻塞DOM Tree的构建过程,脚本由浏览器来进行下载。脚本的执行时机是在DOMContentLoaded事件之前先执行defer中的代码。
- defer是可以保证顺序的,也就是会按照你写的<script src=‘’ defer></script>顺序来执行
2.2 async
3. crossorigin
script 标签的 crossorigin
属性用于配置从第三方服务器加载脚本时的跨域行为。它有以下作用:
-
启用跨域资源共享(CORS)机制:
- 当
crossorigin
属性设置为anonymous
时,浏览器会在请求脚本资源时在请求头中添加Origin
字段,服务器可以根据这个字段决定是否允许跨域访问。 - 当
crossorigin
属性设置为use-credentials
时,浏览器会在请求脚本资源时携带用户凭证(如 Cookies、HTTP 认证等),服务器可以根据这些信息决定是否允许跨域访问。
- 当
-
启用错误报告:
- 当
crossorigin
属性设置时,如果脚本资源加载失败,浏览器会触发error
事件,并在控制台输出详细的错误信息。 - 如果未设置
crossorigin
属性,则脚本资源加载失败时,浏览器不会触发error
事件,也不会在控制台输出错误信息。
- 当
总之, crossorigin
属性可以让开发者更好地跟踪和处理跨域脚本加载的问题。这对于需要从第三方服务器加载脚本的 Web 应用程序很有帮助。
4. 外部依赖sdk.js
对于通过script标签引入进来的sdk.js,即使sdk.js内部有错误,也不会影响当前js代码的执行,这是由于浏览器内部机制做到的。但是
如果调用了sdk.js里的一个方法,这个方法存在问题,那么就会影响当前脚本的执行了,因此需要try…catch…
// sdk.js
function sum(a, b) {
c
return a+b;
}
a
window.sum = sum;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
哈哈哈
<script>
const loadScript = (url, callback) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
const firstScript = document.querySelector('script');
firstScript.parentNode.insertBefore(script, firstScript);
script.onload = function () {
const res = sum(3, 4);
console.log(res)
console.log(22)
callback();
};
};
loadScript('../../../public/test.js', () => {})
console.log(333)
</script>
</body>
</html>
修改如下:
<script>
const loadScript = (url, callback) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
const firstScript = document.querySelector('script');
firstScript.parentNode.insertBefore(script, firstScript);
script.onload = function () {
try {
const res = sum(3, 4);
console.log('res', res);
} catch (e) {
console.log('错误', e);
}
console.log(22);
callback();
};
};
loadScript('../../../public/test.js', () => {});
console.log(333);
</script>
5. 在HTML里通过script标签加载脚本 与 通过js创建script来加载脚本的区别
- 如果在HTML里通过script标签加载脚本如果不写async或者defer,则为同步加载,包括下载js、执行js,是浏览器的行为。
- 如果在js里通过document.createElement(‘script’)方式来加载脚本,则为异步,如果想为同步,则必须在onload回调触发完成。
async componentDidMount() {
await this.loadScript(url1);
await this.loadScript(url2);
}
componentWillUnmount() {
this.removeScript(url1);
this.removeScript(url2);
}
// 加载sdk
loadScript = url => new Promise((resolve, reject) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
const firstScript = document.querySelector('script');
firstScript.parentElement.insertBefore(script, firstScript);
script.onload = resolve;
script.onerror = reject;
});
// 移除sdk
removeScript = target => {
const scriptArrs = Array.from(document.querySelectorAll('script'));
let targetScript = null;
scriptArrs.forEach(item => {
if (item.src === target) {
targetScript = item;
}
});
if (targetScript) {
targetScript.parentElement.removeChild(targetScript);
}
}