wordpress建淘宝客网站吗,重庆网站制作一般多少钱,漂亮的数据型网站,唐山长城网站建设webpack熟悉吗#xff1f;webpack打包流程是什么#xff1f;
webpack打包流程
解析配置文件#xff1a; 读取并解析配置文件#xff0c;并根据配置生成一个Compiler对象。读取入口文件#xff1a;根据配置中的入口文件#xff0c;读取这些文件及其依赖的模块#xff0…webpack熟悉吗webpack打包流程是什么
webpack打包流程
解析配置文件 读取并解析配置文件并根据配置生成一个Compiler对象。读取入口文件根据配置中的入口文件读取这些文件及其依赖的模块并将它们组成一个依赖关系图。解析模块依赖根据模块之间的关系递归解析它们的依赖直到所有依赖都被解析完加载模块根据路径使用对应的loader加载对应的源代码并将其转换成Webpack可处理的形式转换代码根据配置中的插件对加载的模块金雄一系列的转换操作比如压缩、合并、优化等生成代码将所有模块转换后的代码合成一个或者多个文件并输出到相应的输出目录中。
Webpack声明周期
进入编译前此时会初始化Compiler对象开始编译前此时会读取入口文件和依赖并创建依赖关系图开始编译此时会开始编译入口文件和依赖的模块并生成输出文件生成文件前此时可以在插件中处理生成的输出文件完成打包此时可以在插件中进行一些清理工作
你在公司制定前端规范的时候都有哪些内容
命名风格 CSS命名规范 选择器命名一律用小写字母避免使用拼音命名选择器统一采用横线很分隔禁止使用下换线分隔符尽量不要超过4个 JS命名规范 代码中命名不能使用 、 不能以 、_不能以 、不能以、_以及数字结尾代码中命名禁止使用拼音、拼音英文尽量使用驼峰命名法常量统一使用大写单词之间用下换线 _ 隔开TS接口名统一用大写字母 I 作为前缀TS枚举类名称以及其属性名统一使用大写单词之间用下换线 _ 隔开函数名、方法名、属性名、变量名规范 获取单个对象、接口数据使用get作为前缀获取多个对象使用list作为前缀获取数组使用List作为后缀保存、添加使用save、add作为前缀编辑、更新、删除移除使用edit、update、delete、remove作为前缀 代码格式规范 CSS代码格式 一个样式独占一行使用tab或者4个空格选择器单独一行与大括号之间空格样式属性值与冒号之间空格嵌套层级不能过多最多不要超过4层 JS代码格式 尽量使用const和let声明变量大括号使用规范注意前后空格和换行 引号使用 HTML代码中class、id或其他属性都采用双引号JS中字符串使用单引号注意使用 、 !、! 的使用采用4个空格缩进三元表达式在一条表达式中最多出现两次 对象处理 不要修改标准JS对象的原型不要通过原型向对象添加新的属性或方法通过封装导出的方式引用使用对象字面量创建使用展开运算符…复制或者合并数组或对象使用解构获取对象的属性值使用数组对象的方法前如果不确定则需要先进行类型判断使用JSON.parse前需要对变量做类型及JSON格式检查使用定时器后一定要在销毁组件是进行销毁。 注释规约 如果用只说明用途或功能单行注释如果要对参数进行解释多行注释修改代码的同时注释也要进行相应的修改尤其是参数或返回值 小程序跟H5的区别是什么 运行环境的不同 小程序: 小程序的运行环境是基于浏览器内核完全重构的一个内置解析器针对性做了优化配合自己定义的开发语言标准提升了小程序的性能。 脚本内无法使用浏览器中常用的window对象和document对象从源头上避免了DOM的内存泄漏。H5: 无法控制开发人员对DOM的操作容易出现内存泄漏在SPA单页应用还存在页面加载慢的问题。 开发成本不同 小程序: 小程序规范了开发标准则简单得多。前端常见的HTML、CSS变成了微信自定义的WXML、WXSS这样避免了框架五花八门加大了项目接手人员上手维护难度。支付宝小程序可能是AXML、ACSS头条小程序可能是TTML、TTSS等。H5: 涉及开发工具vscode、Atom等、前端框架Angular、react等、模块管理工具Webpack 、Browserify 等、任务管理工具Grunt、Gulp等还有UI库选择、接口调用工具ajax、Fetch Api等、浏览器兼容性 获取系统权限的不同 小程序: 更多的系统权限比如网络通信状态、数据缓存能力等这些系统级权限都可以和小程序无缝衔接。H5: 获取系统权限是大多H5被诟病的地方这也是H5的大多应用场景被定位在业务逻辑简单、功能单一的原因。 运行流畅度的不同 小程序: 小程序它的代码直接在APP上运行通过浏览器双线程UI渲染和业务逻辑分离等技术因此在微信中使用小程序才会比H5流畅很多,首次打开需要几秒的加载时间外小程序各个页面的切换、跳转等体验已经媲美原生App有着同样的柔丝般顺滑的效果。H5: 实际上是打开一个网页而网页需要在浏览器中渲染。所以加载这一过程会给人明显的「卡顿」感觉面对复杂的业务逻辑或者丰富的页面交互时尤为明显。 运维方式不同 小程序: 小程序支持灰度发布、AB测试在出现异常情况下可以实时在管理界面上操作回退。H5: H5如果出现异常问题需要运维人员在生产环境重新部署回滚系统要动到生产环境的系统部署有较大的风险。 用户体验不同 小程序: 由于微信的关系小程序近几年大火用户的接受度和认可度都非常高而且小程序的体验确实要比h5好很多小程序下载到本地可以缓存因此用户体验也更平滑更关键的是用户对小程序的收藏等操作会更自然体验更好不用担心收藏后的东西不好找等情况。H5: H5传统上给人感觉加载始终比较卡而且H5一旦点击退出去后经常会比较难找到对应入口特别是链接深度比较深用户在里面一直点击后用户一旦退出也很难找到自己关注的东西。
vue3中做了哪些优化 源码优化 更好的代码管理方式代码库中各功能区分得更加细致责职分工更加明确package 是可以独立于 Vue.js 使用的例如 reactivity 响应式库能力可以单独依赖这个响应式库而不用依赖整个 Vue.js 减少了引用包的体积大小在 Vue.js 2.x 是做不到这一点的使用了类型语言 TypeScript 重构项目 性能优化 移除了一些冷门的内置方法引入 tree-shaking 的技术在打包中只会引入使用了的代码从而减少了打包后代码的体积 数据劫持优化 数据响应式处理放弃使用 Object.defineProperty改用 new Proxy 监听整一个对象。原因是 Object.defineProperty 不管是否遇到有嵌套层级的对象都需要无脑递归对象逐层监听对象对性能损耗过大。而采用 Proxy 后只有在真正遇到有嵌套层级的对象的时候才会在 getter 的时候逐层递归对每一个对象进行监听处理在很大程度上提升了性能。 编译优化 petch 函数优化通过编译阶段对静态模版的分析编译生成了 Block tree Block tree 是一个将模板基于动态节点指令切割的嵌套区块每个区块内部的节点结构是固定的每个区块只需要以一个 Array 来追踪自身包含的动态节点借助 Block treeVue.js 将 vnode 更新性能由与模板整体大小相关提升为与动态内容的数量相关 在编译阶段还包含了对 Slot 的编译优化、事件侦听函数的缓存优化并且在运行时重写了 diff 算法 语法APi优化composition api Oprion API当组件小的时候这种分类方式一目了然但是在大型项目中一个组件可能有多个逻辑关注点每一个关注点都有自己的 Options当需要修改某一个逻辑关注点时就需要在单个文件中不断上下切换和寻找Composition API将某个逻辑关注点相关的代码全部放在一个函数里这样当需要修改一个功能时就不再需要在文件中翻来覆去
vue2和vue3的响应式有什么区别
Vue3和 Vue2 对比Vue2 的响应式存在很多的问题
初始化时需要遍历对象所有 key如果对象层次较深性能不好通知更新过程需要维护大量 dep 实例和 watcher 实例额外占用内存较多无法监听到数组元素的变化只能通过劫持重写了几个数组方法动态新增删除对象属性无法拦截只能用特定 set/delete API 代替不支持 Map、Set 等数据结构
Vue2 的响应式原理是怎么样的
Vue2 的对象数据是通过 Object.defineProperty 对每个属性进行监听当对属性进行读取的时候就会触发 getter对属性进行设置的时候就会触发 setter
javascript/*** 这里的函数 defineReactive 用来对 Object.defineProperty 进行封装。**/function defineReactive(data, key, val) {// 依赖存储的地方const dep new Dep()Object.defineProperty(data, key, {enumerable: true,configurable: true,get: function () {// 读取数据的时触发在 getter 中收集依赖dep.depend()// 返回结果return val},set: function(newVal) {// 修改数据时触发更新数据并通知dep,更新储存触发watcher更新val newVal// 在 setter 中触发依赖dep.notify()}}) }1. 在Watcher里面进行属性读取读取的时候会把自己设置到一个全局变量中
2. 在Watcher中读取属性会触发getter在getter里面进行依赖收集依赖储存的地方叫Dep在Dep里面就可以把全局变量中的依赖进行收集收集完毕就会把全局依赖变量置空将来数据发生变化的时候就去Dep中把相关的Watcher拿出来执行一遍// Watcher就是所谓的依赖class Watcher {constructor(vm, exp, cb) {this.vm vmthis.getter expthis.cb cbthis.value this.get()}get() {// 读取时依赖收集并储存在Dep中Dep.target thislet value this.getter.call(this.vm, this.vm)// 收集完毕置空全局依赖变量Dep.target undefined// 将最新的结果返回return value}update() {// 数据变化重走一遍watcher,触发getconst oldValue this.valuethis.value this.get()this.cb.call(this.vm, this.value, oldValue)}}总结 Object.defineProperty监听对象的每一个属性当读取数据时会触发getter修改数据时会触发setter在改变数据setter时调用dep中的notify方法notify会遍历依赖后调用watcher依赖器中update方法更新update中会调用get方法重新收集依赖将结果在dep中储存并将结果返回。Dep是依赖的储存器负责添加、删除相关的依赖和通知相关依赖进行相关的操作Watcher是依赖器只有watcher中的get触发才会收集然后调用Dep进行添加、删除依赖操作由于Object.defineProperty无法监听对象的变化所以Vue2中设置了一个Observer类来管理对象的响应式依赖同时会递归检测对象中子数据的变化
为什么 Vue2 新增响应式属性要通过额外的 API$set 这是因为Object.defineProperty只会对属性进行监测而不能对对象镜像监测为了可以监测对象Vue2创建了一个Observer类。 Observer类的作用就是把一个对象全部转换成响应式对象包括子属性当对象新增或者删除属性的是否负责同时对应的Watcher进行更新操作 // $set操作
function set(target, key, val) {const ob target.__ob__// 响应式赋值defineReactive(ob.value, key, val)// 通知dep等同于修改数据触发setter操作ob.dep.notify()return val
}Object.defineProperty 真的不能监听数组的变化吗 Object.defineProperty是可以监听数组的变化但是它是通过下标实际开发基本很少这样处理数据更多的是通过内置方法push、pop、shift、unshift等这些方法是监听不到的所以放弃了Object.defineProperty对数组进行监听采用通过对数组原型上的方法进行重写监听本质还是使用原生Array原型上的方法去操作数组只不过是做了一些逻辑处理数据。 // 拦截器其实就是一个和 Array.prototype 一样的对象。
const arrayProto Array.prototype
const arrayMethods Object.create(arrayProto)
;[push,pop,shift,unshift,splice,sort,reverse
].forEach(function (method) {// 缓存原始方法const original arrayProto[method]Object.defineProperty(arrayMethods, method, {value: function mutator(...args) {// 最终还是使用原生的 Array 原型方法去操作数组return original.apply(this, args)},eumerable: false,writable: false,configurable: true})
})由于Vue2放弃了Object.defineProperty对数组进行监听的方法所以通过下标操作数组是无法实现响应式操作如this.list.length 0
Vue3 的响应式原理是怎么样的 Vue3是通过Proxy对数据事项getter/setter代理从而实现响应式数据. 在副作用函数中读取响应式数据的时候就会触发Proxy的getter 在getter里面把当前副作用函数保存起来将来对应响应式数据发生变化时把之前保存起来的副作用函数取出来执行。 // 使用一个全局变量存储被注册的副作用函数
let activeEffect
// 注册副作用函数
function effect(fn) {activeEffect fnfn()
}
const obj new Proxy(data, {// getter 拦截读取操作get(target, key) {// 将副作用函数 activeEffect 添加到存储副作用函数的全局变量 targetMap 中track(target, key)// 返回读取的属性值return Reflect.get(target, key)},// setter 拦截设置操作set(target, key, val) {// 设置属性值const result Reflect.set(target, key, val)// 把之前存储的副作用函数取出来并执行trigger(target, key)return result}
})
// 存储副作用函数的全局变量
const targetMap new WeakMap()
// 在 getter 拦截器内追踪依赖的变化
function track(target, key) {// 没有 activeEffect直接返回if(!activeEffect) return// 根据 target 从全局变量 targetMap 中获取 depsMaplet depsMap targetMap.get(target)if(!depsMap) {// 如果 depsMap 不存那么需要新建一个 Map 并且与 target 关联depsMap new Map()targetMap.set(target, depsMap)}// 再根据 key 从 depsMap 中取得 deps, deps 里面存储的是所有与当前 key 相关联的副作用函数let deps depsMap.get(key)if(!deps) {// 如果 deps 不存在那么需要新建一个 Set 并且与 key 关联deps new Set()depsMap.set(key, deps)}// 将当前的活动的副作用函数保存起来deps.add(activeEffect)
}
// 在 setter 拦截器中触发相关依赖
function trgger(target, key) {// 根据 target 从全局变量 targetMap 中取出 depsMapconst depsMap targetMap.get(target)if(!depsMap) return// 根据 key 取出相关联的所有副作用函数const effects depsMap.get(key)// 执行所有的副作用函数effects effects.forEach(fn fn())
}
Vue3 中依赖收集的规则首先把响应式对象作为 key一个 Map 的实例做为值方式存储在一个 WeakMap 的实例中其中这个 Map 的实例又是以响应式对象的 key 作为 key, 值为一个 Set 的实例为值。而且这个 Set 的实例中存储的则是跟那个响应式对象 key 相关的副作用函数。副作用函数使用Set类型是因为Set类型能自动去除重复内容对简单类型数据Vue3通过对其做了一层包裹的方式来实现对原始值变成响应式数据的因为简单类型数据是按值传递如函数中形参是简单类型数据但两者没有引用关系改变形参无法影响到实参无法实现响应式。因此 ref 本质是一个实例化的包裹对象来处理对简单类型数据的代理使用一层对象为包裹将简单类型数据放对象里面作为value监听对象即可间接响应式对简单类型数据的响应式方案。
Vue3 中是怎么监测数组的变化
vue2是不可以通过下标对响应式数组进行设置和读取但Vue3是可以的vue3中也需要对数组原型上方法进行重写数组响应式对象使用includes、indexOf、lastIndexOf方法重写因为它们内部的 this 指向的是代理对象并且在获取数组元素时得到的值要也是代理对象所以当使用原始值去数组响应式对象中查找的时候如果不进行特别的处理是查找不到的所以我们需要对上述的数组方法进行重写才能解决这个问题。
Vue2和Vue3的总结
Vue2 是通过 Object.defineProperty 将对象的属性转换成 getter/setter 的形式来进行监听它们的变化当读取属性值的时候会触发 getter 进行依赖收集当设置对象属性值的时候会触发 setter 进行向相关依赖发送通知从而进行相关操作由于 Object.defineProperty 只对属性 key 进行监听无法对引用对象进行监听所以在 Vue2 中创建一个了 Observer 类对整个对象的依赖进行管理当对响应式对象进行新增或者删除则由响应式对象中的 dep 通知相关依赖进行更新操作。Object.defineProperty 也可以实现对数组的监听的但因为性能的原因 Vue2 放弃了这种方案改由重写数组原型对象上的 7 个能操作数组内容的变更的方法从而实现对数组的响应式监听。 Vue3 Vue3 则是通过 Proxy 对数据实现 getter/setter 代理从而实现响应式数据然后在副作用函数中读取响应式数据的时候就会触发 Proxy 的 getter在 getter 里面把对当前的副作用函数保存起来将来对应响应式数据发生更改的话则把之前保存起来的副作用函数取出来执行。Vue3 对数组实现代理时用于代理普通对象的大部分代码可以继续使用但由于对数组的操作与对普通对象的操作存在很多的不同那么也需要对这些不同的操作实现正确的响应式联系或触发响应。这就需要对数组原型上的一些方法进行重写。 比如通过索引为数组设置新的元素可能会隐式地修改数组的 length 属性的值。同时如果修改数组的 length 属性的值也可能会间接影响数组中的已有元素。另外用户通过 includes、indexOf 以及 lastIndexOf 等对数组元素进行查找时可能是使用代理对象进行查找也有可能使用原始值进行查找所以我们就需要重写这些数组的查找方法从而实现用户的需求。原理很简单当用户使用这些方法查找元素时先去响应式对象中查找如果没找到则再去原始值中查找。另外如果使用 push、pop、shift、unshift、splice 这些方法操作响应式数组对象时会间接读取和设置数组的 length 属性所以我们也需要对这些数组的原型方法进行重新让当使用这些方法间接读取 length 属性时禁止进行依赖追踪这样就可以断开 length 属性与副作用函数之间的响应式联系了。
vue3中的watchEffect和watch 在Vue的Composition API中watch和watchEffect都是用于监听响应式数据变化的函数 watch 用于监听一个或者多个响应式数据或计算属性并在它们改变时执行一个函数 immediate 是否立即执行deep 是否深度监听针对对象和数组flush 控制回调何时执行pre、post、 sync watchEffect 用于立即执行函数并监听该函数内部所有引用的响应数据或计算属性
主要区别
自动监听依赖 与 显示声明 watchEffect是自动监听函数内所有引用的响应式而watch需要指明监听的引用数据 立即执行 watchEffect是立即执行一次而watch需要设置immediate选项 旧值与新值 watch回调提供旧值和新值而watchEffect不提供回调参数 多目标监听watch 可以观察多个目标但watchEffect 监听函数内的所有响应式引用
使用场景
watch 需要使用旧值和新值需要基于条件监听处理逻辑需要可控配置 watchEffect 需要多个依赖响应式来触发影响同一个目标的逻辑只关心最新的值
interface和type的区别是什么
类型别名 type type不仅可以用来表示基本类型还可以用来表示对象类型、联合类型、元组和交集 type userName string;
// 联合类型
type userId string | number;
// 元组
type Data [number, string];
type Person {name: string;age: number
}接口 interface interface 仅限描述对象类型 interface Person {name: string;age: number;}都可以描述对象和函数但语法不同 // typetype Ipoint {x: number;y: number;}type SetPoint (x: number, y: number) void;// interfaceinterface IPoint {x: number;y: number;}interface SetPoint {(x: number, y: number): void;}两者都可以被继承混合继承 interface Person {name: string;}interface Student extends Person { id: number; };type Animal {name: string;}type Cart Animal { behavior: leg; };// 混合继承type Student1 Person { id: number; };interface Cart1 extends Animal {say: string;}声明合并
interface 同名声明合并叠加type 不可能同名会报错
vite、webpack、roolup的区别是什么
Webpack介绍
热更新方面Webpack支持HMR当Webpack需要全部冲洗编译并更新效率较低。tree-shakingwebpack2开始支持webpack5支持的更好分包方面Webpack支持代码切割ESM打包现在webpack支持es6module输出
Vite介绍
两部分组成 一个开发服务器它基于原生ES模块提供了丰富的内建功能一套构建指令它是用Rollup打包支持预配置可以输出用于生产环境的优化过的静态资源 主要特点 快速的冷启动直接开启开发服务器不需要进行打包操作不需要分类模块依赖和编译因此启动速度非常快即时的模块热更新真正的按需编译利用现代浏览器支持ES Module的特性当浏览器请求某个模块的时候根据需要对模块的内容进行编译加载请求这种方式大大缩短了编译时间。 优点 vite热更新实现按需加载按模块加载速度快 vite利用HTTP头来加速整个页面的重新加载源代码模块的请求会根据304进行协商缓存依赖模块请求这是通过Cache-Control进行强缓存因此一旦被缓存它们将不需要再次请求热更新原理在热模块HMR方面当修改一个模块的时候仅让浏览器重新请求该模块即可无须像webpack那样需要把该模块的相关依赖模块全部编译一次效率更高。 vite在生产环境通过Rollup进行打包特点打包体积小生成esm模块包特点快 vite在开发环境时基于浏览器支持esm让浏览器解析模块然后服务器按需编译返回。同时基于esbuildgo进行预构建打包不常变动的第三包并用进行缓存。缓存快Vite 使用 esbuild 预构建依赖。Esbuild 使用 Go 编写所以比以 Node.js 编写的打包器预构建依赖快 10-100 倍。 缺点 生态生态不如webpackwepback在于loader和plugin非常丰富prod环境的构建目前用的Rollup原因在于esbuild对于css和代码分割不是很友好还没有被大规模使用,很多问题或者诉求没有真正暴露出来
Rollup介绍 优点 Rollup 是一款 ES Modules 打包器从作用上来看Rollup 与 Webpack 非常类似。不过相比于 WebpackRollup要小巧的多打包生成的文件更小。识别commonJs需要插件热更新Rollup不支持HMR在对js以外的模块的支持上不如webpack但是如果是打包纯js库例如react前期的vue的话使用rollup是很合适的打包的产物比较干净没有webpack那么多工具函数Rollup 的插件机制设计得相对更干净简洁单个模块的 resolve / load / transform 跟打包环节完全解耦所以 Vite 才能在开发时模拟 Rollup 的插件机制并且兼容大部分 Rollup 插件rollup原生支持tree-shaking 缺点 加载其他类型的资源文件或者支持导入 CommonJS 模块又或是编译 ES 新特性这些额外的需求 Rollup需要使用插件去完成rollup并不适合开发应用使用因为需要使用第三方模块而目前第三方模块大多数使用CommonJs方式导出成员并且rollup不支持HMR使开发效率降低
结论
Rollup更适合打包库webpack更适合打包项目应用vite基于rollup实现了热更新也适合打包项目。
promise有哪些方法