前端必须了解的一些基础:HTTP/浏览器机制/前端性能优化/webpack/模块化

263 阅读19分钟

http & 浏览器

状态码

  • 1XX 通知

  • 2XX 成功

    • 200 操作成功

    • 201 服务器创建了新的资源

    • 204 资源存在,但不返回内容

  • 3XX 重定向

    • 301 永久重定向 搜索引擎(SEO)会永久删除旧地址

    • 302 临时重定向 搜索引擎会使用新地址但是保存旧地址 (不推荐使用)

    • 303 查看其它位置 请求返回一个响应文档的URI

    • 304 未修改/强缓存 和上次请求相比没有修改内容,类似204 响应主题为空

    • 307 临时重定向 类似302,但不允许将原本的POST请求重定向到GET上

    • 308 永久重定向 类似301,但不允许将原本的POST请求重定向到GET上

  • 4XX 客户端错误

    • 400 请求错误 通用
    • 401 没有授权 访问需要权限的地址但没有授权
    • 403 服务器拒绝访问 按时资源存在,但不想处理 (服务器封ID,爬虫太多等)
    • 404 资源不存在
    • 408 请求超时 服务器等待请求超时
    • 429 请求次数太多 请求太过频繁,超出限制
  • 5XX 服务端错误

    • 500 服务端错误
    • 501 服务端不支持此http特性
    • 502 网关错误
    • 503 服务器无法处理,可能是资源不足(服务器超载/停机维护)
    • 504 请求网关超时

HTTP2 和HTTP1.1 有什么区别

  1. HTTP/2 采用的是二进制格式,比HTTP\1.1 的文本协议解析起来更高效,错误率更低
  2. HTTP/2 是完全多路服用的,并非有序并阻塞的(线段阻塞)--只需要一个链接即可实现并行
  3. HTTP/2 使用报头压缩,减小开销
  4. HTTP/2 服务器可以将响应主动推送到客户端缓存中

HTTP缓存

强缓存

  • 浏览器控制:后端把需要的资源发过来,并附带发送过期时间,浏览器每次去缓存看一下时间到没到
    1. expires:date:响应expiress字段,后端直接把过期的时间发过来。
    2. cache-control:max-age:后端发送有效时长,浏览器自己倒计时。
    3. 优先 cache-control

协商缓存(对比缓存)

  • 后端发需要的资源发过来,附带上他的标识,浏览器下次请求附带表示,后端对比表示,如果相同就返回304 表示资源没有变化。
    • 通过最后修改时间:last-Modified
      1. 浏览器第一次请求时,给浏览器一个最后的修改时间(last-Modified)
      2. 浏览器请求时带着自己存的最后修改时间(if-Modified-Since)
      3. 后端拿到后和现在的最后修改时间对比,没有变化就返回304,时间一样就按照第一次请求时正常返回。
      4. 浏览器拿到新的last-modified并更新自己的If-Modified-Since
    • 通过标识字符串ETag
      • 响应时携带ETag
      • 请求时携带If-None-Match
      • 服务器对比 新的 ETagIf-None-Match是否相同。
    • 优先使用 ETag

URL输入浏览器后,发生了什么

  • 输入地址后:
    1. DNS解析:浏览器对域名进行解析,将域名地址转化为ip地址。
    2. 建立TCP连接:请求信息(SYN)、确认信息(SYN/ACK)、握手结束(ACK)
    3. 浏览器向web服务器发送http请求
    4. 服务器处理响应、将数据返回给浏览器
    5. 关闭TCP连接(FIN)(ACK)(FIN)(ACK)
    6. 浏览器解析资源

浏览器的渲染流程

  • 基本概念:
    1. DOM:浏览器将HTML解析成的树形结构,简称DOM
    2. CSSOM:浏览器将CSS解析成树形结构,简称CSSOM
    3. Render Tree:将DOM和CSSOM合并后生成的Render Tree
    4. Layout:计算出Render Tree每个结点的具体位置
    5. Paintion:通过显卡,将Layout后的节点内容分别呈现到屏幕上
  • 渲染基本流程:
    1. HTML->DOM:从服务器获取HTML文件,并将HTML文件转化为节点对象,并将节点对象连接起来,形成DOM(文档对象模型)树
    2. CSS-CSSOM:浏览器在构建DOM时会遇到连接CSS的<link>标签,会向服务器请求CSS文件,并将CSS文件转化为节点对象,并将节点对象连接起来形成CSSOM(CSS对象模型)树
    3. DOM+CSSOM->Render Tree:将DOM和CSSOM进行匹配,并且捕获可见内容(除了display:none之类的不可见内容),形成Render Tree渲染树。
    4. Layout:获取渲染树的结构、节点位置和大小,依据盒子模型(每个元素都用一个盒子来表示)这些盒子在页面上进行排列和嵌套。
    5. Paintion:Layout后浏览器将渲染树以像素的形式渲染到页面
  • 注意:
    1. DOM可以进行部分解析,而CSSOM不能进行部分解析
    2. 浏览器先获取JS文件还是CSS文件需要根据实际情况判断,但是浏览器会先构建CSSOM
    3. CSSOM的构建会阻塞渲染,JS的执行也会阻塞DOM,JS的执行要放在CSSOM构建完成后(因为JS既可以操作DOM,又可以操作CSSOM)。
  • 整体流程:
    • 获取HTML -> 构建DOM(部分) ->获取CSS/JS文件 -> 构建CSSOM -> 解析运行JS文件 -> 继续构建DOM -> 形成Render Tree -> Layout -> Paintion

回流(reflow)与重绘(repaint)

回流 Reflow

  • 当Render Tree中的一部分(或者全部)因为元素的尺寸布局隐藏等改变而需要重新构建,称之为回流(reflow)。
  • 至少发生一次:页面在第一次加载的时候,会构建一次Render Tree,发生回流。
  • 在回流的时候,浏览器会使渲染树中受到影响的部分失效,并且重新构造这部分渲染树。
  • 完成回流后,浏览器会重新绘制影响的部分到屏幕中,该过程成为重绘。

重绘 Repaint

  • 当Render Tree中的一些元素需要更新属性,而这些属性值是影响元素的外观、风格,而不会影响布局,比如background-color。称之为重绘(repaint)

区别

  1. 回流必将引起重绘,重绘不一定引起回流。
  2. 页面布局和几何属性(widthheightmarginpaddingdisplay)等发生改变时就会产生回流。

优化

  • 回流比重绘代价更高,回流的花销和Render Tree有多少节点需要重新构建有关系。
  • 浏览器自身的优化:
    • 浏览器会维护一个队列,会把所有引起回流、重绘的操作放到这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会执行队列,进行一个批处理。让多次回流、重绘变成一次回流和重绘。
  • CSS 优化
    1. 使用 transform 代替 top
    2. 使用 visibility(重绘) 代替 display:none(回流)
    3. 避免使用table布局(很小的改动可能引起整个table的重新布局)
    4. 尽可能在DOM树的最末端改变class,(减少回流影响的元素)
    5. 避免设置多层内联样式,CSS选择符从右向左查找,避免节点层级过多。
    6. 将动画效果用到positionabsolute或者fixed的元素上,避免影响其他元素布局。
    7. 控制动画使用requestAnimationFrame
    8. CSS的GPU加速可以让transformopacity这些动画不会引起回流重绘。但是其他属性还是会引起回流和重绘.
  • JS 优化
    1. 频繁操作样式,最好是一次兄重写style属性,或者将样式列表定义为class 一次性更改className
    2. 避免频繁操作DOM,创建documentFragment,在它上面应用到所有DOM操作,最后再把他添加到文档。
    3. 避免频繁读取会引发回流/重绘的属性,如果多次使用,可以先用变量缓存起来。

TCP的三次握手和四次挥手是什么

  • 三次握手:为了保证能建立一个安全可靠的连接
    1. 客户端向服务器发送报文,SYN(表示发起新的连接)
    2. 客户端收到后向客户发送一个确认消息 ACK (表示可以收到客户端消息)
    3. 客户端将收到的确认消息ACK返回给客户端 (表示可以收到服务端数据)
  • 四次握手:
    1. 客户端向服务器发送 FIN (表示想要断开连接)
    2. 服务器端可能还未发送完需要发送的响应,所以只能先返回确认收到 客服端向服务器发送的FIN,但是并不表示服务器已经准备好断开连接。
    3. 等待服务器完全发送完数据,会向客户端发送一个自己已经准备好断开的FIN报文。
    4. 客户端收到服务器的FIN报文后知道服务器要断开连接,之后就可以断开连接了。

对websocket的理解

  • WebScoket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽,并达到实时通讯,它建立在TCP之上,同HTTP一样通过TCP来传输数据
  • websocket和http最大的不同之处
    1. WebSocket是一种双向通讯协议,在建立连接后,WebSocket 服务器和客户端都能主动向对方发送或者接受数据
    2. WebSocket需要类似TCP的客户端和服务器端通过握手链接,链接后才能相互通信。
  • 传统响应模式的处理办法:轮询
    • 客户端通过一定的时间间隔频繁的向服务器请求数据,来保证实时更新。会造成大量的资源浪费。

跨域

什么是跨域

  • 浏览器的同源策略限制
  • 要求协议相同、主机(域名)host相同、端口号port相同

如何解决跨域

  • JSONP : Json padding : callback(json)

    • 在网页上添加一个script标签向服务器请求json数据,服务器将参数放在指定名字的回调函数中返回回来
    • 缺点:只支持get不支持post
  • CORS :W3C标准 从根本上解决跨域问题

    • 服务端设置响应头 Access-Cotrol-Allow-Origin
  • webpack 的本地代理 (开发时)

    • 浏览器请求代理服务器,代理服务器请求服务器,服务器响应代理服务器,代理服务器响应浏览器

    • devServer 中配置 proxy

      devServer:{
          port:8080,
          proxy:{
              '/api':{
                  traget:'http://'
              }
          }
      }
      
  • 通过websocket协议

    • 浏览器和服务器全双工通信,无关http,但是需要通过http协议建立连接

Options 参数

  • 在正式跨域请求之前,浏览器会根据需要,发起一个"PreFlight"(也就是option)请求,用来让服务端返回允许的方法(如getpost)、被夸云访问的源Origin,还有是否需要Credentials(认证信息)
  • 简单请求不会触发"PreFlight" (除了复杂请求的就是简单请求)
  • 复杂请求会触发"PreFlight"
    1. 使用put或者delete方法
    2. 发送json格式的数据(content-type:application/json)
    3. 请求中带有自定义的请求头
  • 为什么复杂请求需要options参数
    • 复杂请求可能对服务器数据产生副作用,对数据进行修改。

CDN

什么是CDN

  • 内容分发网络
  • CDN加速需要依靠各个网络节点,会从多个CDN服务器中选出最近的节点(缓存服务器)返回资源
  • 好处:主要是加速静态资源的访问

Webpack

什么是Webpack

  • webpack是一个模块化打包工具,可以分析代码的依赖关系,通过转换形成文件依赖更为简单的项目文件
  • webpack的核心:Entry(入口)、Output(出口)、loader、plugins、mode

有什么用

  • 代码转换:将浏览器不能直接运行的代码转换成可以运行的代码 (TS、SCSS)
  • 文件优化:压缩JS、CSS、HTML代码,压缩合并图片(小图片base64)
  • 代码分割:提取多个页面的公共代码,提取首屏不需要的代码让其异步加载
  • 模块合并:将多个模块和文件合并为一个文件,减少文件复杂的依赖关系
  • 热刷新:提高开发效率
  • 代码校验:检测是否规范(ESLint)

常见的 loader

  • style-loader : 将编译完成的样式挂载到style标签上
  • css-loader : 用于识别.css文件,配合style-loader使用
  • less-loader :处理less文件
  • sass-loader:处理sass/scss文件
  • postcss-loader:补充css样式各种浏览器内核前缀、将px转化为vm、处理css兼容性问题
  • file-loader:打包静态资源 除了html/css/js 的其他资源
  • url-loader:可以将小图片改为date-URL (base64)格式,减少http请求次数
  • html-loader::处理html中的img资源
  • ts-loader:打包编译ts文件
  • eslint-loader: 需排除第三方库(node_modules) 需配置package.json
  • babel-loader:将ES6转化为ES5语法 解决js兼容问题 @babel/core @babel/preset-env babel-polyfill (解决全局变量:Map、Set、Promise之类的新特性)
  • thread-loader: 多进程打包 进程启动也有开销,项目大的时候可以使用

常见的 plugin

  • html-webpack-plugin:打包HTML文件、自动引入js、css等资源
  • mini-css-extract-plugin:将css提取成单独文件,而不是内嵌在js中
  • optimize-css-assets-webpack-plugin:压缩css体积
  • workbox-webpack-plugin :渐进式网络开发应用程序(可离线访问)

mode的配置 devServer

devServer: {
// 项目构建后路径
contentBase: resolve(__dirname, 'build'),
// 启动 gzip 压缩
compress: true,
// 端口号
port: 3000,
proxy:{
 '/api':{
    traget:'http://'
  }
},
// 自动打开浏览器
open: true
}

webpack 性能优化

  • HMR : 热模块替换hot module replacement

    devServer:{
        //开启HMR热替换
        hot:true;
    }
    
  • source-map :映射源文件的错误信息、方便开发

    devtool: 'source-map'  会生成map格式的文件,里面包含映射关系的代码
    devtool: 'inline-source-map' 不会生成map格式的文件,包含映射关系的代码会放在打包后生成的代码中
    devtool: 'inline-cheap-source-map' 一是将错误只定位到行,不定位到列。升打包构建的速度。
    devtool: 'inline-cheap-module-source-map' module会映射loader和第三方库
    devtool: 'eval'eval的方式生成映射关系代码,效率和性能最佳。但是当代码复杂时,提示信息可能不精确。
    
    开发环境:'cheap-module-eval-source-map'
    生产环境:'cheap-module-source-map'
    
  • oneOf : 将loader放入oneOf:[]中 每个类型的文件只会被一个loader匹配

  • babel缓存:第二次构建会读之前的缓存 在babel-loader中添加 cacheDirectory:true

  • tree-shaking:删除js代码死区的代码 (默认开启)

    1. 只对 ES Module 起作用 不对commonjs起作用  因为commonjs是动态到处的
    2. babel默认转换为 commonjs  需要配置 
        	.babelrc的{module:false} 
    	和  .package.json 的 {sideEffects:false}  才可以 tree-shaking
    
  • lazy loading :webpack 异步引入模块 加速首页访问速度

    // 将代码打包为不同的 chunk
    optimization:{
        splitChunks:{
            chunks:'all'
        }
    } 
    
  • thread-loader: 多进程打包 进程启动也有开销,项目大的时候可以使用

{
    loader:'thread-loader',
    options:{
        worker:2 //两个进程
    }
}
  • PWA:workbox-webpack-plugin 渐进式网络开发应用程序(可离线访问)

webpack 的运行时代码

  • 通过 webpack_modules_ 维护一个所有模块的数组

  • 通过 webpack_require_ 手动实现加载一个模块

  • 通过 webpack_require_(0) 运行第一个模块(入口模块)

    // 将模块放入 _webpack_modules__
    const _webpack_modules__ = [
        ()=>{ `模块0 入口模块`},
        (module,_webpack_require__)=>{`模块1 第一个模块`}
    ]
    
    // _webpack_require__ 手动实现commonjs的模块加载
    const _webpack_require__ = (modulesId){
        // 创建模块
        const module={exports:{}}
        //调用执行 _webpack_modules__ 中管理的模块
        const m = _webpack_modules__[modulesId](module,_webpack_require__)
        return module.exports;
    }
    
    // _webpack_require__(0) 运行入口模块
    _webpack_require__(0)
    

前端性能优化

懒加载

  • 使用异步加载资源。当资源被使用或即将被使用时再进行加载。

  • 通过 setTimeout 或者 setInterval 设置加载延迟

  • 条件触发 :当触发某些条件后再开始加载某些资源

  • 事件监听:可视区域 (项目多时浪费资源,加载后依旧监听事件)

    // 先将路径保存到自定义属性 data-src 中
    <img data-src='1.jpg'>
    if(imageTop<window.innerHeight){
     	// 将 data-src 赋值给 src 属性,开始加载图片
        const dataSrc = image.getAttribute('data-src')
        image.setAttribute('src',dataSrc)
    }
    
  • IntersectionObserver API (浏览器API)(交叉观察)

    //  callback 会在目标元素(DOM节点) 能看见和不能看见的时候各触发一次
    const observer = new intersectionObserver(callback)
    //开启观察  DOM节点  oberver.observe(DOM节点)
    //结束观察  DOM节点   observer.unobserve(DOM节点)
    
    
    //观察每一个image
    images.forEach(image=>{
        observer.observe(image)
    })
    
    //callback 自带接受一个数组参数,存放每个oberverDOM元素的观察信息
    const callback = entries =>{
        entries.forEach(entry=>{
            if(entry.isIntersection){   // isIntersection 属性为是否交叉 true/fase
                const image = entry.target   // target 属性为当前DOM元素
                const dataSrc = image.getAttribute('data-src')
                image.setAttribute('src',dataSrc)
                //加载后取消观察
                observer.unobserve(image)
            }
        })
    }
    
  • img标签 loading='lazy' 属性

    <img src='1.jpg' loading='lazy'>    // loading = 'eager | lazy'
    

预加载

  • 再需要资源之前提前将资源加载好,例如:通过 new Image() 并设置其src属性来下载图片,当时用到相同的src就会从缓存中读取,而不是重新下载

懒加载 和 预加载 的区别

  • 两种技术的本质:
    • 预加载是提前加载。预加载则会增加服务器前端压力。
    • 懒加载是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用

节流

  • 设置节流阀,让事件再某个时间段内只能执行一次 (一般为先执行,再限制)

    // 主要功能
    let mainFun = () => { console.log('主要功能') }
    
    // 包裹功能的节流函数
    function throttle(fn,time){
        let canActive = true
        return function(){
            if(canActive){
                canActive = false
                setTimeout(()=>{           //如果需要原始的this对象,可以通过apply绑定
               	    mainFun()
                    canActive = true
            	},time)
            }
        }
    }
    
    //将主要功能通过节流函数包裹
    let mainFunThrottle = throttle(mainFun, 3000)
    
    //测试节流
    setInterval(() => {
      mainFunThrottle()     // 每3秒触发一次
    }, 1000)
    
    
    

防抖

  • 在一段时间内多次触发事件仅仅执行一次 (一般为先限制,后执行)

    // 主要功能
    let mainFun = () => {
      console.log('主要功能')
    }
    
    //防抖函数
    let antiShake = function (fn, time) {
      let hasTimer
      return function () {
        if (hasTimer) {
          clearTimeout(hasTimer) // 如果存在,删除旧的,创建新的,按照新的计时
        }
        hasTimer = setTimeout(() => {
          mainFun()
        }, time)
      }
    }
    
    //将主要功能通过防抖函数包裹
    let mainFunAntiShake = antiShake(mainFun, 1000)
    
    let i = 0
    let timeId = setInterval(() => {
      mainFunAntiShake()   //仅仅触发1次
      if (i < 30) {
        i++
      } else {
        clearInterval(timeId)
      }
    }, 100)
    

节流 和 防抖 的区别

  • 区别:
    • 节流:通常为限执行,后限制,在规定时间内触发多次只有第一条生效
    • 防抖:通常为先限制,后执行,在规定时间内触发多次只有最后一条生效
  • 注意:
    • 注意包裹后因为setTimeout引起的this指向改变问题,可以通过 apply(context , arguments) 改变

CDN加速

  • 通过cdn加速静态资源访问

webpack性能优化

  • 开发优化:
    • HMR : 热模块替换hot module replacement
    • source-map :映射源文件的错误信息、方便开发
    • oneOf : 将loader放入oneOf:[]中 每个类型的文件只会被一个loader匹配
    • babel缓存:第二次构建会读之前的缓存 在babel-loader中添加 cacheDirectory:true
    • thread-loader: 多进程打包 进程启动也有开销,项目大的时候可以使用
  • 生产优化:
    • lazy loading :webpack 异步引入模块 加速首页访问速度
    • 代码体积优化:
      • tree-shaking:删除js代码死区的代码 (默认开启)
      • js代码默认压缩
      • mini-css-extract-plugin:将css提取成单独文件,而不是内嵌在js中
      • optimize-css-assets-webpack-plugin:压缩css体积
      • html-webpack-plugin:打包压缩HTML文件、自动引入js、css等资源
    • http请求:
      • url-loader:减少http请求次数

首屏加载优化

  • 图片:
    • 懒加载
    • 精灵图
    • url-loader (base64)
  • Gzip压缩
  • 首屏服务端渲染SSR
  • CDN加速
  • 合理使用浏览器缓存

SEO优化

  • 合理的title标签

    <title>标题</title>
    
  • description

    <meta name='Description' Content='网页简述'>
    
  • keywords

    <meta name='Keywords' Content='关键字1,关键字2,关键字3,'>
    
  • 语义化HTML

    <header></header>
    <nav></nav>
    <article></article>
    <aside></aside>
    <section></section>
    <footer></footer>
    <p></p>
    <strong></strong>
    
  • 图片添加 alt 属性

  • a标签加 title 属性

前端网络安全

XSS 是什么 如何解决

  • XSS:Cross Site Scripting 跨站脚本攻击

    • 向网页注入恶意指令代码
    • 例如:注入HTML 注入JavaScript 甚至服务端语言
  • 如何解决

    • 过滤 & 转义

    • 虚拟DOM也可以防止XSS

    • CSP(内容安全策略)

      • 在 HTML 的 Head 中添加如下 Meta 标签,将在符合 CSP 标准的浏览器中使非同源的 script 不被加载执行。

        <meta http-equiv="Content-Security-Policy" content="script-src 'self'">
        
      • CSP 有两种策略类型:

        'Content-Security-Policy' 对不安全的资源会进行阻止执行
        'Content-Security-Policy-Report-Only' 只会进行数据上报,不会有实际的阻止。
        
      • 注意: 如果页面很多可以通过统一设置HTTP Header

         Content-Security-Policy:srcipt-src 'self' '*.qq.com'
        

CSRF 是什么 如何解决

  • CSRF 攻击全称跨站请求伪造(Cross-site Request Forgery)
    • 攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF的另一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。
    • 自动防御策略:浏览器同源策略(跨域)
    • 主动防御:通过Token验证,后端不要再GET接口做用户操作

前端模块化

什么是前端模块化,有什么好处

  • 产生原因:前端页面复杂度越来越高,规模越来越大,不同代码之间的相互依赖显得非常不清楚,多人开发十分不方便。

  • 模块化是开发的一种管理方式,将不同功能的代码和资源分别作为一个模块。

  • 模块化的好处

    • 解决命名冲突问题
    • 提高代码复用性
    • 提高代码的可维护性
    • 提高代码灵活性,按需导入,灵活使用
    • 有利于多人共同开发

常见的前端模块化规范

  • AMD
  • CMD
  • Commonjs
  • ESM(ES6模块化规范)

CommonJS

  • Node 应用采用的CommonJS模块化规范,每个文件就是一个模块,有自己的作用域,在一个文件里面定义的变量、函数、类都是私有的,对其他文件不可见。在服务器端,模块加载是运行时同步加载。在浏览器端,模块需要提前编译打包(不能再浏览器中直接使用CommonJS规范)

  • 特点:

    • 模块中的代码有自己的作用域,不会污染全局
    • 模块可以被多次加载,但只在第一次运行,运行后会缓存起来,之后直接读缓存结果。想要模块重新运行,必须清除缓存。
    • 模块加载顺序就是其再代码中出现的顺序
  • 基本用法

    • 暴露模块

      module.exports = value  或
      exports.xxx = value
      
    • 引入模块

      const xxx = require('aaa')
      // 如果是第三方模块  aaa 为模块名即可
      // 如果是自定义模块  aaa 为模块文件路径
      
  • 本质:

    • CommonJS中mondule代表当前模块,是一个对象。他的exports属性是对外接口,加载模块加载的是该模块的module.exports属性
    • require的基本功能是用于加载模块文件:读入并执行一个JavaScript文件,然后返回该模块的exports对象
    • CommonJS的就加载机制:输入的是被输出的值的浅拷贝,也就是说,模块内部的变化影响不到输出后的值(原始类型,会被缓存),可以通过清除缓存或者使用函数引用(闭包)

ES6 模块化(ESM)

  • ES6 模块化的设计思想是尽量的静态化,在编译时就能确定模块的依赖关系,以及输入和输出的变量,是官方的语言层面的模块化设计,可以再浏览器中直接使用。

  • 基本用法:

    • 导入导出

      //   通过 export 导出
      export const name= 'zhangsan'
      export let age = 15
      // 通过 import 导入   (通过 as 起别名)
      import {name,age as Age} from './xxx.js'
      
      // 通过 export default 默认导出  (只能有一个默认导出)
      export default function(){}
      // 通过 import 导入
      import myFn from './xxx.js'
      
  • 本质:

    • export语句输出的接口是与其对应值的动态绑定,通过该接口可以获取到模块内部实时的数据

    • ES6 模块化为官方语言层面的模块化设计,可以在浏览器中直接使用,是未来的趋势

      <script type='module' src='xxx.js'></script>
      

ESM 和 CommonJS的区别

  • CommonJS 模块输出的是一个值的拷贝,ESM输出的是值的只读引用
    • CommonJS 是值的拷贝,将值缓存,缓存之后无法改变,除非清理缓存
    • ESM 是动态只读引用,不会缓存值,可以实时获取模块内部数据变化
  • CommonJS 的require() 是同步加载模块,ESM的import是异步加载模块
  • CommonJS 是运行时加载,ESM是编译时加载或者静态加载
  • CommonJS加载有缓存,ESM加载没有缓存
  • CommonJS 加载的是整个模块,ESM 可以单独加其中一些方法(按需导入
  • CommonJS模块中的this指向当前模块(module.exports) ,ESM中指向undefined