onload什么时候触发?

2,396 阅读1分钟

先说结论:动态插入script、或者发起请求会影响onload的触发时机。

MDN的解释

The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images, scripts, links and sub-frames have finished loading.

加载事件在文档加载过程结束时触发。此时,文档中的所有对象都在DOM中,所有图像、脚本、链接和子帧都已完成加载。

这里有提到“所有图像、脚本、链接和子帧都已完成加载”;

如果我们在js过程中动态插入脚本会怎么样呢?

下面代码你的预计输出可能是:

add scripts
add scripts end
onload
add scripts onload
xhr not async

实际输出:

add scripts
add scripts end
xhr not async
add scripts onload 
onload

代码

<!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>
	<link rel="preload" href="./load.js" as="script">
</head>
<body>
	<p>预计输出:</p>
	<div>add scripts</div>
	<div>add scripts end</div>
	<div>onlaod</div>
	<div>add scripts onload</div>
	<div>xhr not async</div>
	<br/>
	<p>实际输出</p>
	<div>add scripts</div>
	<div>add scripts end</div>
	<div>xhr not async</div>
	<div>add scripts onload</div>
	<div>onlaod</div>

	<script>
		window.onload = function(){
			console.log("onlaod");
		}
	</script>
	<script>
		console.log('add scripts');
		
		var script = document.createElement('script');
		script.src = 'https://cdn.jsdelivr.net/npm/jquery@2.2.4/dist/jquery.min.js';
		script.onload = function(){
			console.log('add scripts onload'); // 会带onload之前触犯
		}
		document.body.appendChild(script);
		console.log('add scripts end');
	</script>

	<script>
		function xhr(url) {
			return new Promise(function (resolve, reject) {
				var xhr = new XMLHttpRequest();
				xhr.addEventListener('load', function () {
					if (xhr.readyState !== 4) {
						return;
					}
					if (xhr.status >= 400) {
						return reject(getError(`Request failed with status code ${xhr.status} for url: ${url}`));
					}
					var result;
					try {
						result = JSON.parse(xhr.responseText);
					} catch (e) {
						return reject(getError(`Json is invalid for url: ${url}`));
					}
					resolve(result);
				});
				xhr.addEventListener('error', reject);
				// 这里采用同步请求,所以第三个参数把async=false,同步会延迟onload的触犯
				xhr.open('GET', url, false);
				xhr.send();
			});
		}

		// 同步请求
		xhr('https://d.17win.com/galaxy/configuration/xqy-front-manage/pre/servyou-pre/hashConfig.json').then(function(){
			console.log('xhr not async')
		})
				
	</script>
</body>
</html>