js文件同步和异步的引入问题

同步加载和异步加载

  • 同步加载:同步加载是指在主线程上按顺序执行代码,当遇到加载资源(例如网络请求、读取文件)时,主线程会停止执行后续的代码,等待资源加载完成后再接着执行后续的代码。这样的方式可能会导致用户体验不佳,因为当资源加载耗时长时,用户需要等待较长时间才能看到后续的处理结果。
  • 异步加载:异步加载则不会阻塞主线程,它会在后台加载资源,同时主线程还会继续执行后续的代码。当资源加载完成后,通常通过回调函数或者Promise(.then方法)来获取资源,并对其进行处理。这样的方式可以避免阻塞主线程,提升用户体验。

异步加载就是多个资源同时加载,同步加载就是同一时刻只加载一个资源。
JavaScript中,由于它的单线程特性,通常推荐使用异步加载的方式来处理网络请求、文件操作等耗时操作。

JS模块的加载方法

CommonJS

使用CommonJS规范require()函数加载模块是同步的,也就是说在加载完模块之前,后续代码不会执行。这在服务器端环境中非常有用,因为模块文件通常都已经在本地,加载很快,而且一般需要在服务器启动时加载所有必要的模块。

ES6

ES6的模块既可以使用同步加载也可以使用异步加载,取决import的使用方式:

  • 同步加载:同步加载是使用import的静态导入方式,结合from使用 :
    静态加载没有返回值,静态加载是一个语句,

    import module from 'module-name';
    

    在module模块加载完成之前是不会执行下面的代码的,所以在模块导入后的所有地方都可以直接使用该模块。

  • 异步加载:异步加载是使用import的动态导入方式,模块作为import的参数使用(可以是路径名也可以是模块名):
    动态加载的返回值是一个Promise对象,所以可以直接使用.then函数编写回调函数

    import('module-name').then((module) => {
      // 你可以在这里使用模块
    });
    

    也可以使用async/await语法,

    async function loadModule() {
      try {
        const module = await import('module-name');
        // 使用这个模块
      } catch (error) {
        // 处理加载错误
      }
    }
    

ES6的<script>标签的加载方式

  • <script >导入 —— 同步加载
    <script src="">标签并不是使用模块化的导入导出方式,可以使用该标签加载执行JS文件,但是其中所有的变量和函数都会在全局作用域中。
    <script src="">的导入方式是同步导入。当解析到<script src=“”>的时候会暂停解析HTML,去下载javascript文件,等文件下载完成之后再继续解析剩余的HTML文件。

  • <scrtpt type="module">导入 —— 异步加载
    使用这种方式导入的文件是异步导入,使用<scrtpt type="module">导入的时候浏览器会采用严格模式,并且模块会自动地被异步加载

    <script type="module">
      import {foo} from './foo.js';
      foo();
    </script>
    

    或者使用src导入文件:

    <script type="module" src="./main.js"></script>
    

    main.js

    import {foo} from './foo.js';
    foo();
    
  • <script src=“”>的异步加载
    可以在<script>标签中添加asyncdefer属性来使文件异步加载。

    • async 属性:这会使得浏览器非阻塞(异步)地下载 JavaScript 文件,但是一旦文件下载完成,浏览器会立刻解析并执行这个文件,这导致了 HTML 的解析可能会被暂时阻塞。多个包含 async 属性的 <script> 标签,它们的执行顺序无法保证,完全由加载完成的时间顺序决定。

    • defer 属性:这也会使得浏览器非阻塞(异步)地下载 JavaScript 文件,但是与 async 不同的是,包含 defer 属性的 <script> 标签会在整个 HTML 文档解析完成之后才开始执行。如果有多个包含 defer 属性的 <script> 标签,它们的执行顺序会按照在 HTML 文件中的出现顺序来执行。

  • <script>标签异步引入的时候如何判断模块加载完成
    使用<script src="">标签的异步引入,不像直接在js模块中的异步引入可以使用回调函数和Promise来编写异步模块加载完成之后的逻辑,但是我们有其他的解决办法:

    • 使用事件监听器

      <script>
      document.querySelector('script[src="script.js"]').addEventListener('load', function() {
        // script.js文件加载完成之后执行的逻辑代码
      });
      </script>
      <script async src="script.js"></script>
      
    • 使用onload事件监听

      <script type="module" src="./main.js" onload="init()"></script>
      <script>
        function init() {
          // main.js 已加载完毕,你可以在这里使用它导出的函数和变量
        }
      </script>
      
    • 如果被异步加载的文件可以手动编写,可以使用设置全局回调函数的方式:

      <script>
      window.scriptLoaded = function() {
        //  script.js文件加载完成之后执行的逻辑代码
      };
      </script>
      <script async src="script.js"></script>
      

      然后在 script.js 中的最后一行调用 scriptLoaded 函数:

      // script.js文件的逻辑代码
      window.scriptLoaded();
      
    • 如果是<script type="module">逻辑代码</script>的方式,可以直接使用动态import的特性

      <script type="module">
      import('script.js').then((module) => {
        //  script.js文件加载完成之后执行的逻辑代码
      });
      </script>
      
  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JavaScript 是一门单线程的编程语言,意味着它在任意给定的时刻只能执行一个任务。这是因为 JavaScript 在最初设计时是作为浏览器脚本语言而诞生的,用于操作网页的 DOM(文档对象模型)。 在 JavaScript 中,任务按照它们被调用的顺序执行,这种方式称为同步执行。当一个任务执行时,其他任务必须等待它的完成才能继续执行。这种同步执行的特性可以确保数据的一致性,但也可能导致阻塞,特别是在执行耗时较长的任务时。 为了解决阻塞问题JavaScript 引入异步执行的概念。通过异步执行,可以让某些任务在后台执行,而不会阻塞其他任务的执行。常见的异步操作包括网络请求、文件读写和定时器等。在 JavaScript 中,通常使用回调函数、Promise、async/await 等方式来处理异步操作。 回调函数是最早被广泛使用的异步处理方式。通过将一个函数作为参数传递给异步操作,在操作完成后调用该函数来处理结果。然而,使用回调函数嵌套多层会导致代码可读性和维护性的降低,这就是所谓的"回调地狱"问题。 为了解决回调地狱问题,Promise 和 async/await 出现了。Promise 是一种用于处理异步操作的对象,它可以链式调用,避免了回调函数嵌套的问题。而 async/await 是基于 Promise 的语法糖,使异步代码看起来更像同步代码,更易于理解和编写。 总结起来,JavaScript 是单线程的,但通过异步执行可以提高程序的性能和响应速度。同步执行保证了数据的一致性,而异步执行允许在后台处理耗时操作,提高了用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值