面试常见问题js同异加载

336 阅读2分钟

同步加载

这是大家熟知的js加载方式,这种方式是同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止了后续的解析,因此停止了后续的文件加载(如图像)、渲染、代码执行。

<script src="http://yourdomain.com/script.js"></script>

异步加载

既然有同步那必然就会有异步,js加载的异步是什么样的呢,看代码 以上两种都是异步,特别之处就是加了defer和async属性。 defer和async的区别在于:

async 脚本在script文件下载完成后会立即执行,并且其执行时间一定在 window的load事件触发之前。这意味着多个async脚本很可能不会按其在页面中的出现次序顺序执行。
defer执行时机为DOM解析完成后,documentDOMContentLoaded事件触发之前。浏览器确保多个 defer 脚本按其在HTML页面中的出现顺序依次执行。

值得注意的是

在异步加载的时候,无法使用 document.write 输出文档内容。 在同步模式下,document.write 是在当前 script所在的位置输 出文档的。
而在异步模式下,浏览器继续处理后续页面内容,根本无法确定 document.write 应该输出到什么位置,所以异步模式下 document.write 不可行。
而到了页面已经 onload 之后,再执行 document.write 将导致当前页面的内容被清空,因为它会自动触发 document.open 方法。

封装一个函数兼容性的异步加载js文件并且可以按需执行该文件里面的函数(按需加载)

方法一

<script>
        function loadScript(url,callback){
            //url是按需加载的js文件
            //callback是按需加载的js文件中某个函数
 
            // 1. 创建一个script标签
            var script = document.createElement('script');    
            // 处理ie的兼容
            if(script.readyState){
                script.onreadystatechange = function(){
                    // 如果script已经下载完成
                    if(script.readyState == 'complete' || script.readyState == 'loaded'){
                        callback();
                    }
                }
            }else{
                // 监听script的下载的状态 当状态变为下载完成后 再执行callback
                script.onload = function(){
                    callback();
                }
            }
            //在后面引入的目的是如果在IE上如果下载太快(比读程序还快)
            //IE的readystatechange 事件检测状态码的时候,它早已经从loading变成complete或者loaded(以极快的速度加载完了文件,你还没来得及检测)
            // 那你再检测它就不会变了,它一直都是complete或者loaded
            //这个时候就是马后炮了,检测也没用了。
            // 2. 给script标签添加src 引入一个js文件
            script.src = url;
            // 3. 追加到body
            document.body.appendChild(script);
        }
    </script>

方法二

let loadUrls=[]
function loadJs(src) {
    return new Promise((resolve, reject) => {
        if (loadUrls.indexOf(src)>-1) {//如果注册过该JS了 直接返回
            resolve()
            return
        }
        let script = document.createElement('script');
        script.type = "text/javascript";
        script.src = src;
        document.body.appendChild(script);

        script.onload = () => {
            loadUrls.push(src)//注册成功添加到已注册列表
            resolve();
        }
        script.onerror = () => {
            reject();
        }
    })
}

export default loadJs