前端知识总结

1、聊聊 Redux 和 Vuex 的设计思想

Redux 和 Vuex 都是用于状态管理的工具,分别用于 React 和 Vue.js 应用程序。它们的设计思想都受到了 Flux 架构的影响,但在细节和实现上有一些差异。

Redux 设计思想:

  • 单一数据源:Redux 倡导将整个应用的状态存储在单一的状态树中,这样可以方便地追踪和管理状态的变化。
  • 状态只读:Redux 中的状态是只读的,不能直接修改,只能通过派发动作(actions)来描述对状态的更改。
  • 纯函数更新状态:Redux 的状态更新由纯函数来处理,称为 "reducer",接收先前的状态和动作,返回新的状态,保证状态的更新是可预测的。
  • 单向数据流:Redux 强调数据的单向流动,即从视图(View)到状态(State),再到派发动作(Actions)和状态更新(Reducer),最终再回到视图的渲染,这种单向流动简化了状态的管理和调试。
  • 中心化存储:Redux 的状态被集中存储在一个 "store" 中,使得状态的管理和共享更加直观和简单。

Vuex 设计思想:

  • 集中式存储:Vuex 将整个应用的状态集中存储在一个 "store" 中,通过定义各种状态、动作、突变和获取方法,方便地进行状态的管理和共享。
  • 组件通信:Vuex 可以用于实现组件之间的通信,可以通过 "store" 中的状态和派发动作来实现组件之间的数据共享。
  • 响应式更新:Vuex 使用 Vue.js 的响应式系统,使得状态的变化能够自动更新视图,无需手动触发视图的更新。
  • 插件扩展:Vuex 支持插件机制,可以通过插件来扩展和增强 "store" 的功能,例如添加日志、持久化等功能。

共同点:

  • Redux 和 Vuex 都强调了状态的集中化管理,将应用的状态存储在一个统一的地方,方便进行管理和共享。
  • 它们都使用了类似的设计思想,例如单一数据源、状态只读和纯函数更新状态等,这些思想都来自于 Flux 架构。

不同点:

  • Redux 是一个独立的状态管理库,而 Vuex 是专门为 Vue.js 设计的状态管理插件。
  • Redux 使用的是纯 JavaScript,而 Vuex 则利用了 Vue.js 的响应式系统来实现状态的更新和响应式更新。
  • 在使用上,Vuex 可以更加无缝地集成到 Vue.js 应用中,而 Redux 需要额外的适配和中间件。

2、介绍下观察者模式和订阅-发布模式的区别,各自适用于什么场景

区别:

  • 关系:观察者模式中被观察者和观察者有直接依赖关系,而订阅-发布模式中发布者和订阅者通过消息中心进行解耦。
  • 通知方式:观察者模式是被观察者主动通知观察者,而订阅-发布模式是发布者不需要知道订阅者的存在,由消息中心进行通知。
  • 灵活性:订阅-发布模式更加灵活,允许订阅者选择监听自己感兴趣的事件,而观察者模式是被观察者将状态变化通知给所有观察者。

适应场景:

观察者模式适用于被观察者和观察者之间有直接依赖关系的场景,而订阅-发布模式适用于更加松散的通信场景,允许解耦发布者和订阅者,提高系统的灵活性和可维护性。

3、介绍模块化发展历程。可从IIFE、AMD、CMD、CommonJS、UMD、webpack(require.ensure)、ES Module、<script type="module"> 这几个角度考虑。

模块化发展历程经历了多个阶段,不同的模块化方案在不同的时期逐渐发展和应用。以下是模块化发展历程的主要阶段:

  • IIFE (Immediately Invoked Function Expression):
    IIFE 是最早期的模块化解决方案之一。它通过使用立即执行函数表达式来创建一个私有的作用域,并将需要暴露的功能通过返回值的方式暴露给全局环境。这样可以避免全局命名冲突,但缺点是需要手动管理模块之间的依赖关系。
  • AMD (Asynchronous Module Definition):
    AMD 是由 RequireJS 提出的模块化规范。它允许模块异步加载,并且在模块加载完成后执行回调。AMD 使用 define 函数定义模块,并使用 require 函数来异步加载模块。AMD 方案适用于浏览器环境,可以在运行时动态加载依赖模块。
  • CMD (Common Module Definition):
    CMD 是由 SeaJS 提出的模块化规范,与 AMD 类似,也支持模块异步加载,但 CMD 更加推崇就近依赖,即在需要使用模块时再去加载。CMD 使用 define 和 require 函数来定义和加载模块,适用于浏览器环境。
  • CommonJS:
    CommonJS 是一种用于服务器端的模块化规范,Node.js 是其最典型的实现。CommonJS 使用 require 和 module.exports 来定义和导出模块。CommonJS 支持同步加载模块,适用于服务器端环境。
  • UMD (Universal Module Definition):
    UMD 是一种通用的模块化方案,兼容 CommonJS、AMD 和全局变量的方式。它能够在不同的环境中运行,使得模块可以同时适用于浏览器和服务器端。
  • webpack (require.ensure):
    webpack 是一种现代的打包工具,支持各种模块化规范和打包方式。在早期版本中,webpack 使用 require.ensure 来实现异步加载模块,使得代码在运行时动态加载所需的模块,从而实现按需加载和分块打包。
  • ES Module (ES6 Module):
    ES Module 是 ECMAScript 6 中引入的官方标准模块化方案,使用 import 和 export 关键字来定义和导出模块。ES Module 支持静态分析,使得浏览器可以在解析阶段就静态确定依赖关系,实现了更好的性能和开发体验。
  • <script type="module">:
    <script type="module"> 是 HTML5 中引入的用于加载 ES Module 的方式。当浏览器遇到带有 type="module" 的 <script> 标签时,会将其视为 ES Module,并进行静态分析和按需加载依赖模块。

随着 JavaScript 生态系统的不断发展,ES Module 成为了 JavaScript 模块化的主流标准,逐渐取代了其他模块化方案。现代的构建工具如 webpack 和 Rollup 已广泛支持 ES Module,并且浏览器也逐渐完整支持 ES Module,使得开发者可以更方便地使用标准的模块化规范。

4、async/await实现原理

async/await 是 ECMAScript 2017(ES8)引入的语言特性,用于简化 JavaScript 中的异步编程,使得异步代码的写法更加像同步代码,增加代码的可读性和可维护性。async/await 是建立在 Promise 基础上的语法糖,它的实现原理可以简单概括为以下几点:

  • async 函数:
    使用 async 关键字声明的函数被称为 "异步函数"。在函数内部,可以使用 await 关键字来暂停函数的执行,等待一个 Promise 对象返回结果。异步函数在执行时会立即返回一个 Promise 对象,可以通过这个 Promise 对象获取函数的返回值或捕获函数内部的异常。
  • await 关键字:
    在异步函数内部,await 关键字后面可以跟一个 Promise 对象。当遇到 await 时,函数会暂停执行,直到 Promise 对象的状态变为 resolved(已完成)或 rejected(已拒绝)。如果 Promise 被解决(resolved),await 表达式会返回 Promise 的结果;如果 Promise 被拒绝(rejected),await 表达式会抛出异常,并可以通过 try...catch 捕获。
  • 转换成 Promise:
    异步函数内部的 await 表达式会将后面的 Promise 对象转换成 Promise,即使后面不是 Promise 对象,await 也会将其转换成 Promise 对象。这样,即使 await 后面是一个同步操作或普通值,也能够按照 Promise 的方式进行处理。
  • 异步任务的顺序执行:
    async/await 可以实现异步任务的顺序执行,即使用 await 可以将异步任务的执行顺序变得像同步代码一样。在遇到 await 时,函数会等待前一个异步任务完成后再继续执行后续代码。
  • 错误处理:
    使用 try...catch 可以捕获异步函数内部的异常。如果在 await 表达式中的 Promise 被拒绝(rejected),可以通过 catch 捕获并处理异常。

综上所述,async/await 是通过 Generator 和 Promise 的组合来实现的。当使用 async 关键字声明一个函数时,函数内部的代码会被转换成一个状态机(StateMachine),其中每个 await 表达式都是一个状态,每个状态都对应于一个 Promise 的 resolve 或 reject,从而实现了异步任务的顺序执行和错误处理。这样使得异步代码看起来更像同步代码,提高了代码的可读性和可维护性。

5、为什么通常在发送数据埋点请求的时候使用的是 1x1 像素的透明 gif 图片?

  1. 没有跨域问题,一般这种上报数据,代码要写通用的,img 天然支持跨域;(排除 ajax)
  2. 不会阻塞页面加载,影响用户的体验,只要 new Image 对象就好了, 通过它的onerror和onload事件来检测发送状态;(排 除 JS/CSS 文件资源方式上报)
  3. 在所有图片中,简单、安全、相比PNG/JPG体积最小;(比较 PNG/JPG)(tip:最小的BMP文件需要74个字节,PNG需要67个字节,而合法的GIF,只需要43个字节)

6、typescript有哪些优缺点

TypeScript 是 JavaScript 的一个超集,它为 JavaScript 添加了静态类型检查和一些面向对象编程的特性。

优点总结:更早发现 BUG;代码可预测;方便重构;丰富的 IDE 支持,智能提示、自动补全、代码导航;提供面向对象的写法

优点:

  • 静态类型检查:TypeScript 引入了静态类型系统,可以在开发阶段发现类型错误,减少因类型导致的潜在问题。类型检查可以提高代码的健壮性和可维护性。
  • 更好的代码提示和补全:TypeScript 提供了更强大的代码提示和补全功能,可以帮助开发者更快地编写代码,减少代码错误和重构成本。
  • 代码可读性和可维护性:通过使用类型注解和接口,代码的含义和目的更加清晰,使得代码更易于理解和维护。
  • 支持最新的 ECMAScript 特性:TypeScript 可以编译为不同版本的 ECMAScript,允许使用最新的 JavaScript 特性,同时在不同浏览器和环境中保持兼容性。
  • 渐进式迁移:TypeScript 可以逐渐引入到现有的 JavaScript 项目中,支持部分代码使用 TypeScript,逐步迁移,降低迁移成本。
  • 社区支持:TypeScript 有一个活跃的社区,拥有丰富的资源和工具支持。

缺点:

  • 学习成本:TypeScript 增加了一些新的概念和语法,对于不熟悉 TypeScript 的开发者来说,学习成本可能会稍高。
  • 需要编译:由于 TypeScript 是 JavaScript 的超集,需要通过编译器将 TypeScript 代码编译为普通的 JavaScript,增加了构建步骤和复杂性。
  • 增加了一定开发成本:引入类型检查和接口定义需要额外的开发成本,特别是对于一些简单的项目或小规模团队,可能会觉得有些冗余。
  • 项目初期的额外开发成本:在项目初期,由于代码量较少,可能感受不到 TypeScript 带来的明显好处,而需要投入一定时间和精力来定义类型和接口。

总体来说,TypeScript 是一个强大的工具,可以提高代码质量和可维护性,特别适用于大型项目或团队合作的场景。但对于一些简单的项目或小规模团队,使用 TypeScript 可能会带来一些额外的开发成本。因此,是否使用 TypeScript 需要根据具体项目的规模、复杂性和开发团队的状况来决定

7、介绍一下webpack/vite

Webpack 和 Vite 都是现代前端构建工具,用于打包和构建 Web 应用程序。它们有一些区别,主要体现在以下几个方面:

  • 构建速度:
    Vite 在开发环境下具有非常快的冷启动速度。它通过利用原生 ES 模块的特性,将依赖项进行按需引入,并使用服务端渲染的方式提供了一个快速的开发体验。相比之下,Webpack 的冷启动速度相对较慢,尤其在大型项目中会有明显的延迟。
  • 开发体验:
    Vite 支持原生 ES 模块的导入方式,不需要进行打包,所以在开发时的编译速度非常快,支持热更新,开发者可以更迅速地看到改动的效果。而 Webpack 在开发环境下通常需要进行较多的打包和编译,所以开发体验相对较慢一些。
  • 构建方式:
    Webpack 是传统的打包工具,通过使用各种 loader 和 plugin,可以处理各种类型的文件,并将它们打包成最终的生产文件。Vite 则采用了新的构建方式,将开发环境和生产环境进行了分离,通过原生 ES 模块的特性在开发时实现快速的冷启动,而在生产环境时使用 Rollup 进行打包,以产出高效的生产构建。
  • 插件生态:
    Webpack 有着非常丰富的插件生态,社区支持广泛,可以应对各种复杂的场景。Vite 虽然是一个新兴的构建工具,插件生态相对较少,但也在不断发展壮大。
  • 支持文件类型:
    Webpack 可以处理几乎所有类型的文件,包括 JavaScript、CSS、图片、字体等。Vite 主要关注于前端开发过程中的 JavaScript、CSS 和 HTML 等文件。
  • 生产构建性能:
    ​​​​​​​在生产环境下,Vite 通过使用 Rollup 来构建项目,具有出色的打包性能,能够生成更小、更高效的生产构建。

Vite 总结一下,最大的特点就是:

  • 基础 ESM,实现快速启动和模块热更新。
  • 在服务端实现按需编译。

总体而言,Vite 适用于开发阶段的快速开发和热更新,而 Webpack 则更适用于生产环境的复杂场景和强大的插件生态。选择使用哪个构建工具取决于项目的需求和优先考虑的方面。在新项目中,尤其是对开发体验有较高要求的项目中,Vite 可能是更好的选择。而对于复杂的项目和需要丰富插件支持的项目,Webpack 仍然是一个稳定可靠的选择。

8、webpack5做了哪些升级

性能:Webpack5相对于Webpack4有更好的性能表现,尤其是在构建速度和Tree Shaking方面。

模块联邦:Webpack5引入了模块联邦的概念,可以让多个Webpack构建的应用程序共享模块,从而减少了代码冗余。

持久性缓存:Webpack5引入了持久性缓存,通过使用持久性哈希来生成文件名,可以更好地利用浏览器缓存,从而提高应用程序的加载速度。

解析器:Webpack5支持WebAssembly模块、JSON模块和TypeScript模块的解析。

构建输出:Webpack5支持输出多个bundle,通过设置output.chunkFilename参数来实现。

移除插件:Webpack5移除了一些不常用的插件,例如UglifyJsWebpackPlugin和CommonsChunkPlugin。

9、Webpack Tree Shaking的原理

Webpack 的 Tree Shaking 是一种用于消除 JavaScript 中未使用代码的优化技术,通过 Tree Shaking,Webpack 可以检测和移除项目中未使用的模块和代码,从而减少生成的生产包大小,提高应用的性能。

Tree Shaking 的原理可以简单地概括为以下几个步骤:

  • ES6 模块引入:Tree Shaking 只对 ES6 模块(使用 import 和 export)生效。Webpack 通过识别 ES6 模块语法,确定哪些模块是可被 Tree Shaking 的目标。
  • 静态分析:Webpack 使用静态分析技术检测应用代码中的模块和变量的引用关系。它会从入口模块(entry module)开始,递归地分析所有引用的模块,构建一个模块之间的依赖关系图(dependency graph)。
  • 标记未使用代码:在静态分析的过程中,Webpack 标记所有被引用的模块和变量,而未被引用的模块和变量会被标记为未使用。
  • 剔除未使用代码:一旦构建了依赖关系图并标记了未使用的代码,Webpack 就会根据标记信息,将未使用的模块和变量从最终的生产包中剔除掉。

需要注意的是,Tree Shaking 的成功与否取决于代码的实际使用情况。如果代码中存在动态引入模块的情况(例如使用变量或函数来动态地引入模块),Webpack 无法在构建时确定模块的具体引用关系,这样的模块将无法被正确地 Tree Shaking。

为了确保 Tree Shaking 的有效性,需要遵循一些最佳实践:

  • 使用 ES6 模块语法:确保代码中使用 ES6 的 import 和 export 来引入和导出模块。
  • 避免动态引入模块:尽量避免在条件语句、循环或函数中动态地引入模块,以保证在构建时可以静态分析模块的引用关系。
  • 使用纯函数和常量:使用纯函数和常量来引入模块,避免在模块导入语句中使用复杂的表达式。

10、介绍下 webpack 热更新原理,是如何做到在不刷新浏览器的前提下更新页面

首先,介绍webpack-dev-server:
webpack-dev-server 主要包含了三个部分:
1.webpack: 负责编译代码
2.webpack-dev-middleware: 主要负责构建内存文件系统,把webpack的 OutputFileSystem 替换成 InMemoryFileSystem。同时作为Express的中间件拦截请求,从内存文件系统中把结果拿出来。
3.express:负责搭建请求路由服务。

其次,介绍工作流程:
1.启动dev-server,webpack开始构建,在编译期间会向 entry 文件注入热更新代码;
2.Client 首次打开后,Server 和 Client 基于Socket建立通讯渠道;
3.修改文件,Server 端监听文件发送变动,webpack开始编译,直到编译完成会触发"Done"事件;
4.Server通过socket 发送消息告知 Client;
5.Client根据Server的消息(hash值和state状态),通过ajax请求获取 Server 的manifest描述文件;
6.Client对比当前 modules tree ,再次发请求到 Server 端获取新的JS模块;
7.Client获取到新的JS模块后,会更新 modules tree并替换掉现有的模块;
8.最后调用 module.hot.accept() 完成热更新

11、Koa 中间件原理

在 Node.js 中,Koa 是一个轻量级的 Web 框架,它通过中间件(Middleware)机制来处理 HTTP 请求和响应。Koa 的中间件可以简要概括如下:

  • 中间件函数:Koa 中间件是一个函数,它接收两个参数,分别是 ctx(上下文对象)和 next(下一个中间件函数)。中间件函数的主要作用是处理请求和响应,以及决定是否将控制权交给下一个中间件。
  • 执行顺序:在 Koa 中,中间件函数的执行顺序是按照代码的书写顺序依次执行。每个中间件函数在执行时可以选择调用 next(),以将控制权交给下一个中间件函数。如果某个中间件函数没有调用 next(),则后续的中间件将不会被执行。
  • 上下文对象:每个中间件函数的 ctx 参数是一个包含请求和响应相关信息的上下文对象。ctx 中包含了诸如请求的 URL、请求头、请求体、响应状态码、响应体等信息。中间件可以在 ctx 对象上读取请求信息或设置响应信息。
  • 错误处理:Koa 中使用 try-catch 来处理中间件中的错误。如果某个中间件函数抛出了异常或产生了错误,Koa 会立即跳转到最近的错误处理中间件来处理异常。
  • 异步支持:由于 Koa 基于 Promise,它天生支持异步操作。在中间件函数中,可以使用 async/await 来处理异步操作,使得异步代码的编写更加简洁。

中间件原理:

koa 把很多 async 函数组成一个处理链,每个 async 函数都可以做一些自己的事情,然后用 await next() 来调用下一个 async 函数。我们把每个 async 函数称为 middleware,这些 middleware 可以组合起来,完成很多有用的功能。koa 的中间件是通过 Async/Await 实现的,中间件执行顺序是“洋葱圈”模型。中间件之间通过 next 函数联系,当一个中间件调用 next() 后,会将控制权交给下一个中间件,直到下一个中间件不再执行 next() 时沿路返回,依次将控制权交给上一个中间件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值