【前端知识点】

虚拟 dom:

虚拟 dom 就是 vue 通过 js 对象渲染虚拟 dom 的,虚拟 dom 的 js 对象包含节点的类型、属性、子节点等信息,这些虚拟 dom 节点会构成一棵树形结构,用来表示整个页面的结构。
当 vue 组件更新时,会通过 diff 算法进行计算,diff 算法是先比较记录再批量更新操作。
diff 算法流程分别有(新 dom 树会和缓存的旧 dom 树进行比较)
根节点比较、逐层比较:从树的根节点开始,确定根节点是否相同、找出节点直接的差异(如果节点类型不同则会停止对子级节点比较,但只是节点属性、内容不同则会记录,并继续对子级的比较记录)。这只是 diff 算法的第一步,用于记录确定哪些部分需要更新。
同级比较:在同一级的节点直接进行比较、找出增删改的节点。
叶子节点比较:对叶子节点进行比较
key比较:如果节点有唯一标识符 key,则 diff 算法会使用这些表示来更精确的比较节点

示例:

<div id="app">
  <h1>Hello, {{ name }}!</h1>
  <p>This is a paragraph.</p>
</div>

虚拟 dom 的 js 树形对象结构如下

{
  tag: 'div',
  attrs: {
    id: 'app'
  },
  children: [
    {
      tag: 'h1',
      children: [
        'Hello, ',
        {
          data: 'name' // 数据绑定的部分
        },
        '!'
      ]
    },
    {
      tag: 'p',
      children: [
        'This is a paragraph.'
      ]
    }
  ]
}

双向数据绑定的原理

采用数据劫持结合发布者-订阅者模式的方式,data 数据在初始化的时候,会实例化一个 Observe 类,在它会将 data 数据进行递归遍历,并通过 Object.defineProperty 方法,给每个值添加上一个 getter 和一个 setter。在数据读取的时候会触发 getter 进行依赖(Watcher)收集,当数据改变时,会触发 setter,对刚刚收集的依赖进行触发,并且更新 watcher 通知视图进行渲染。

slot 插槽

默认插槽:又名匿名插槽,当 slot 没有指定 name 属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。
具名插槽:带有具体名字的插槽,也就是带有 name 属性的 slot,一个组件可以出现多个具名插槽。
作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。

keep-alive 的理解

keep-alive 是 Vue.js 的一个内置组件。它能够将不活动的组件实例保存在内存中,而不是直接将其销毁,它是一个抽象组件,不会被渲染到真实 DOM 中,也不会出现在父组件链中。
keep-alive 内部其实是一个函数式组件,没有 template 标签。在 render 中通过获取组件的 name 和 include、exclude 进行匹配。匹配不成功,则不需要进行缓存,直接返回该组件的 vnode。

匹配成功就进行缓存,获取组件的 key 在 cache 中进行查找,如果存在,则将他原来位置上的 key 给移除,同时将这个组件的 key 放到数组最后面(LRU)也就实现了 max 功能。

不存在的话,就需要对组件进行缓存。将当前组件 push(key)添加到尾部,然后再判断当前缓存的 max 是否超出指定个数,如果超出直接将第一个组件销毁(缓存淘汰策略 LRU)。

LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

$nextTick 原理及作用

Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用。 nextTick 是将回调函数放到一个异步队列中,保证在异步更新 DOM 的 watcher 后面,从而获取到更新后的 DOM。

因为在 created()钩子函数中,页面的 DOM 还未渲染,这时候也没办法操作 DOM,所以,此时如果想要操作 DOM,必须将操作的代码放在 nextTick()的回调函数中。

Vue 模版编译原理

模版编译主要过程:template —> ast —> render,分别对象三个方法

parse 函数解析 template
optimize 函数优化静态内容
generate 函数创建 render 函数字符串
调用 parse 方法,将 template 转化为 AST(抽象语法树),AST 定义了三种类型,一种 html 标签,一种文本,一种插值表达式,并且通过 children 这个字段层层嵌套形成了树状的结构。

optimize 方法对 AST 树进行静态内容优化,分析出哪些是静态节点,给其打一个标记,为后续更新渲染可以直接跳过静态节点做优化。

generate 将 AST 抽象语法树编译成 render 字符串,最后通过 new Function(render)生成可执行的 render 函数

路由守卫

全局前置钩子:
beforeEach:在每次路由跳转之前触发。可以用于进行全局的导航守卫,例如检查路由权限验证、路由跳转控制
beforeResolve:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后触发。常用于等待异步逻辑完成后再跳转。
afterEach:在导航成功完成之后触发。适合用于执行一些页面切换后的全局操作,比如页面埋点或者页面加载完成的动画。

路由独享守卫:
beforeEnter:在路由配置中独立定义的守卫,针对某个具体路由生效。可以用于对特定路由进行额外的验证或处理。

组件内钩子:
beforeRouteEnter:在进入路由对应的组件之前被调用,此时组件实例还未创建,无法访问 this。可以通过传入回调函数来访问组件实例。
beforeRouteUpdate:在当前路由改变,但是该组件被复用时调用。可以用于在路由参数发生变化时更新组件数据。
beforeRouteLeave:在离开当前路由对应的组件时触发。可以用于在离开页面前进行一些确认操作,比如弹出确认框或者保存数据。

设置动态路由

params 传参
query 传参

mixin 和 mixins 区别

mixin 用于全局混入,会影响到每个组件实例,通常插件都是这样做初始化的。
mixins 应该是最常使用的扩展组件的方式了。如果多个组件中有相同的业务逻辑,就可以将这些逻辑剥离出来,通过 mixins 混入代码,比如上拉下拉加载数据这种逻辑等等。

v-model 是如何实现的,语法糖实际是什么?

Vue 中数据双向绑定是一个指令 v-model,可以绑定一个响应式数据到视图,同时视图的变化能改变该值。

当作用在表单上:通过 v-bind:value 绑定数据,v-on:input 来监听数据变化并修改 value
当作用在组件上:本质上是一个父子通信语法糖,通过 props 和$emit 实现。

Computed 和 Watch 的区别

computed 计算属性,通过对已有的属性值进行计算得到一个新值。它需要依赖于其他的数据,当数据发生变化时,computed 会自动计算更新。computed 属性值会被缓存,只有当依赖数据发生变化时才会重新计算,这样可以避免重复计算提高性能。

watch 用于监听数据的变化,并在变化时执行一些操作。它可以监听单个数据或者数组,当数据发生变化时会执行对应的回调函数,和 computed 不同的是 watch 不会有缓存。

MVVM 的理解

MVVM 是一种软件架构模式,MVVM 分为 Model、View、ViewModel:

Model 代表数据模型,数据和业务逻辑都在 Model 层中定义;
View 代表 UI 视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。

async/await 的理解

通过 async 关键字声明一个异步函数, await 用于等待一个异步方法执行完成,并且会阻塞执行。
async 函数返回的是一个 Promise 对象,如果在函数中 return 一个变量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。如果没有返回值,返回 Promise.resolve(undefined)

说说你对 Promise 的理解

Promise 是异步编程的一种解决方案,将异步操作以同步操作的流程表达出来,避免了地狱回调。

Promise 的实例有三个状态:

Pending(初始状态)
Fulfilled(成功状态)
Rejected(失败状态)

Promise 的缺点:

无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

promise.all()可以完成并行任务,将多个 Promise 实例数组,包装成一个新的 Promise 实例,返回的实例就是普通的 Promise。有一个失败,代表该 Primise 失败。当所有的子 Promise 完成,返回值时全部值的数组
promise.race()类似 promise.all(),区别在于有任意一个完成就算完成
promise.allSettled() 等所有 Promise 执行完毕后,不管成功或失败, 都会把每个 Promise 状态信息放到一个数组里面返回

原型

prototype : js 通过构造函数来创建对象,每个构造函数内部都会一个原型 prototype 属性,它指向另外一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。
proto: 当使用构造函数创建一个实例对象后,可以通过proto访问到 prototype 属性。
constructor:实例对象通过这个属性可以访问到构造函数

原型链

每个实例对象都有一个proto属性指向它的构造函数的原型对象,而这个原型对象也会有自己的原型对象,一层一层向上,直到顶级原型对象 null,这样就形成了一个原型链。
当访问对象的一个属性或方法时,当对象身上不存在该属性方法时,就会沿着原型链向上查找,直到查找到该属性方法位置。
原型链的顶层原型是 Object.prototype,如果这里没有就只指向 null

对闭包的理解已经它的使用场景

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。
闭包优点:
创建全局私有变量,避免变量全局污染
可以实现封装、缓存等

闭包缺点:
创建的变量不能被回收,容易消耗内存,使用不当会导致内存溢出
解决: 在不需要使用的时候把变量设为 null

使用场景:
用于创建全局私有变量
封装类和模块
实现函数柯里化

闭包一定会造成内存泄漏吗?
闭包并不一定会造成内存泄漏,如果在使用闭包后变量没有及时销毁,可能会造成内存泄漏的风险。只要合理的使用闭包,就不会造成内存泄漏。

对作用域、作用域链的理解

作用域是一个变量或函数的可访问范围,作用域控制着变量或函数的可见性和生命周期。
全局作用域:可以全局访问
最外层函数和最外层定义的变量拥有全局作用域
window 上的对象属性方法拥有全局作用域
为定义直接复制的变量自动申明拥有全局作用域
过多的全局作用域变量会导致变量全局污染,命名冲突

函数作用域:只能在函数中访问使用哦
在函数中定义的变量,都只能在内部使用,外部无法访问
内层作用域可以访问外层,外层不能访问内存作用域

ES6 中的块级作用域:只在代码块中访问使用
使用 ES6 中新增的 let、const 什么的变量,具备块级作用域,块级作用域可以在函数中创建(由{}包裹的代码都是块级作用域)
let、const 申明的变量不会变量提升,const 也不能重复申明
块级作用域主要用来解决由变量提升导致的变量覆盖问题

作用域链:

变量在指定的作用域中没有找到,会依次向一层作用域进行查找,直到全局作用域。这个查找的过程被称为作用域链。

JavaScript 共有八种数据类型

分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。
这些数据可以分为原始数据类型和引用数据类型(复杂数据类型),他们在内存中的存储方式不同。

堆: 存放引用数据类型,引用数据类型占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址,如 Object、Array、Function。
栈: 存放原始数据类型,栈中的简单数据段,占据空间小,属于被频繁使用的数据,如 String、Number、Null、Boolean。

Sass、Less 的区别

他们都是 CSS 预处理器,是 CSS 上的一种抽象层。他们是一种特殊的语法/语言编译成 CSS。都支持变量、混合(mixin)和嵌套规则

语法:
Sass 使用严格的缩进来表示代码块和层级关系。支持条件语句,可以使用 if{}else{},for{}循环等等,而 Less 不支持,可以用来生成重复的样式规则。
Less 使用类似于更接近传统的 CSS 的语法,但添加了一些额外的功能,如变量、混合(mixin)和嵌套规则。

扩展性:
Sass 提供了更多的功能和内置函数,如条件语句、循环等,使得它在某种程度上更加强大和灵活。
Less 相对来说功能较为简单,但也足够满足大多数的样式表需求。

变量符不一样,Less 是@,而 Scss 是$。

进程和线程

进程(Process)
进程是计算机中正在运行的程序的实例,一个进程就是一个程序运行实例。它拥有独立的内存空间、代码和数据,并且由操作系统负责调度和管理。每个进程在执行时都会分配独立的内存空间,不同进程之间的内存是隔离的,一个进程的错误不会直接影响其他进程。 进程之间通过进程间通信(IPC)机制来交换数据和进行通信,常见的 IPC 方式包括管道、消息队列、共享内存等。进程的切换开销较大,因为需要保存和恢复进程的完整状态,涉及到内存保护和虚拟内存的切换。

线程(Thread)
线程是进程的子任务,一个进程可以包含多个线程。它们共享相同的代码和数据,但拥有独立的执行栈和寄存器集合。多个线程可以在同一进程内并发执行,共享进程的资源,如内存空间、打开的文件等。线程间的通信和数据交换比进程间的通信更加方便,因为它们共享相同的地址空间。线程的切换开销较小,因为线程共享进程的地址空间,切换时不需要切换内存页表,速度较快。

区别:
进程和线程都可以实现并发执行,但进程是独立的执行实体,而线程是依赖于进程的。
进程之间资源相互隔离,线程共享所属进程的资源。
创建和销毁线程的开销较小,而创建和销毁进程的开销较大。
多线程程序的编程复杂度通常比单线程程序高,但多线程可以更好地利用多核处理器来提高程序的执行效率。

浏览器有哪些进程

主进程:负责处理用户输入、渲染页面等主要任务。
渲染进程:渲染进程负责解析 HTML、CSS 和 JavaScript,并将网页渲染成可视化内容。
GPU 进程:负责处理浏览器中的 GPU 加速任务。
网络线程:网络进程负责处理浏览器中的网络请求和响应,包括下载网页和资源等。
插件进程:负责浏览器插件运行。

Cookie、LocalStorage、SessionStorage 区别

Cookie
大小只有 4kb
跨域不能共享
不安全,容易被劫持
只存在请求头中

SessionStorage
存储在内存中,体积相对较大
页面关闭,数据会消失
相对 Cookie 安全

LocalStorage
体积大,可以存储更多内容。
生命周期长,除非手动删除,不然会一直存在
存储在硬盘中,不会像 Cookie 一样被请求携带

什么是同源策略

跨域问题其实就是浏览器的同源策略造成的。 同源指的是:协议、端口号、域名必须一致。

如何解决跨越问题

CORS:服务器开启跨域资源共享
JSONP:利用<script>标签不存在跨域限制,只支持 GET 请求,且不安全。
nginx 代理跨域
nodejs 中间件代理跨域,通过 node 开启一个代理服务器。

webpack 的构建流程

初始化参数:从配置文件或者 shell 语句中读取合并参数
开始编译:用参数初始化 Compiler 对象,加载所有配置的插件,执行 run 方法。
确定入口:根据 entry 参数找到入口文件
编译模块:从⼊⼝⽂件出发,调⽤所有配置的 Loader 对模块进⾏翻译,再找出该模块依赖的模块,再递归本步骤直到所有⼊⼝依赖的⽂件都经过了本步骤的处理;
完成模块编译:在经过第 4 步使⽤ Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
输出资源:根据⼊⼝和模块之间的依赖关系,组装成⼀个个包含多个模块的 Chunk,再把每个 Chunk 转换成⼀个单独的⽂件加⼊到输出列表,这步是可以修改输出内容的最后机会;
输出完成:在确定好输出内容后,根据配置确定输出的路径和⽂件名,把⽂件内容写⼊到⽂件系统

总结就是三个阶段:
初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
编译:从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理
输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中

Webpack 的热更新(Hot Module Replacement)?原理是什么?

Webpack 的热更新(Hot Module Replacement,简称 HMR),在不刷新页面的前提下,将新代码替换掉旧代码。
HRM 的原理实际上是 webpack-dev-server(WDS)和浏览器之间维护了一个 websocket 服务。当本地资源发生变化后,webpack 会先将打包生成新的模块代码放入内存中,然后 WDS 向浏览器推送更新,并附带上构建时的 hash,让客户端和上一次资源进行对比。客户端对比出差异后会向 WDS 发起 Ajax 请求获取到更改后的内容(文件列表、hash),通过这些信息再向 WDS 发起 jsonp 请求获取到最新的模块代码。

如何提高 webpack 的打包速度

利用缓存:利用 Webpack 的持久缓存功能,避免重复构建没有变化的代码。可以使用 cache: true 选项启用缓存。
使用多进程/多线程构建 :使用 thread-loader、happypack 等插件可以将构建过程分解为多个进程或线程,从而利用多核处理器加速构建。
使用 DllPlugin 和 HardSourceWebpackPlugin: DllPlugin 可以将第三方库预先打包成单独的文件,减少构建时间。HardSourceWebpackPlugin 可以缓存中间文件,加速后续构建过程。
使用 Tree Shaking: 配置 Webpack 的 Tree Shaking 机制,去除未使用的代码,减小生成的文件体积
移除不必要的插件: 移除不必要的插件和配置,避免不必要的复杂性和性能开销。

如何减少打包后的代码体积

代码分割(Code Splitting):将应用程序的代码划分为多个代码块,按需加载。这可以减小初始加载的体积,使页面更快加载。
Tree Shaking:配置 Webpack 的 Tree Shaking 机制,去除未使用的代码。这可以从模块中移除那些在项目中没有被引用到的部分。
压缩代码:使用工具如 UglifyJS 或 Terser 来压缩 JavaScript 代码。这会删除空格、注释和不必要的代码,减小文件体积。
使用生产模式:在 Webpack 中使用生产模式,通过设置 mode: 'production’来启用优化。这会自动应用一系列性能优化策略,包括代码压缩和 Tree Shaking。
使用压缩工具:使用现代的压缩工具,如 Brotli 和 Gzip,来对静态资源进行压缩,从而减小传输体积。
利用 CDN 加速:将项目中引用的静态资源路径修改为 CDN 上的路径,减少图片、字体等静态资源等打包。

宏任务和微任务

Javascript 是单线程语言,所以一切 Javascript “多线程” 都是单线程模拟出来的既然是单线程,就会出现拥挤,也就有了 “同步任务和异步任务。”
队列分为两种:宏任务队列和微任务队列,宏任务(macrotask)和微任务(microtask)是与事件循环(event loop)相关的概念,用于管理异步操作的执行顺序。

同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入 Event Table 并注册函数。
当指定的事情完成时,Event Table 会将这个函数移入 Event Queue。
主线程内的任务执行完毕为空,会去 Event Queue 读取对应的函数,进入主线程执行。
上述过程会不断重复,也就是常说的 Event Loop(事件循环)。
Alt text

  • 同步任务(普通任务):例如全局代码、函数调用等,按照代码的顺序同步执行,不会被放入宏任务队列或微任务队列中。
  1. 宏任务(macrotask)
  • 宏任务包括:

  • Script(脚本任务):整体代码块作为一个宏任务执行。

  • setTimeout 和 setInterval:通过 setTimeoutsetInterval 添加的任务会被放入宏任务队列中,在指定的时间后执行。

  • I/O 操作:包括读写文件、网络请求等异步操作,它们会被放入宏任务队列中,等待执行。

  • UI 渲染:浏览器需要执行的与页面渲染相关的任务,比如重绘和回流,也属于宏任务。

  • 事件处理程序:当用户触发事件(比如点击、滚动等)时,事件处理程序会被添加到宏任务队列中,等待执行。

  • requestAnimationFrame:用于在浏览器下一次重绘之前执行指定的任务,也属于宏任务。

  • 宏任务会被放入宏任务队列中,在事件循环的每一轮中执行一个宏任务。

  • 当执行完一个宏任务后,事件循环会检查微任务队列,然后执行所有微任务,再进入下一个宏任务。

  • 发起者:宿主(Node、浏览器)

  • 会触发新一轮 Tick

  • 微任务的执行时长会影响到当前宏任务的时长。比如一个宏任务在执行过程中,产生了 100 个微任务,执行每个微任务的时间是 10 毫秒,那么执行这 100 个微任务的时间就是 1000 毫秒,也可以说这 100 个微任务让宏任务的执行时间延长了 1000 毫秒。所以你在写代码的时候一定要注意控制微任务的执行时长

  1. 微任务(microtask)
  • 微任务包括:
  • Promise:当 Promise 对象状态变为 resolved 或 rejected 时,与之相关联的回调函数会被放入微任务队列中,等待执行。
  • MutationObserver:用于监视 DOM 变化的 API,当指定的 DOM 变化发生时,注册的回调函数会被放入微任务队列中。
  • process.nextTick(Node.js 环境下):用于将回调函数放入微任务队列,确保在当前操作完成后立即执行。
  • queueMicrotask:用于将一个微任务函数放入微任务队列中。

微任务会在每一轮事件循环中的特定阶段执行,通常在当前宏任务执行完毕后、下一个宏任务开始之前执行。事件循环会首先处理所有的微任务,然后再执行下一个宏任务。这种机制确保微任务能够及时响应异步操作的完成,并且在当前任务执行结束后立即执行。

  • 微任务会被放入微任务队列中,在每个宏任务执行完毕之前会立即执行微任务。
  • 微任务队列优先级高于宏任务队列,即微任务队列中的任务会在下一个宏任务之前执行完。
  • JS 引擎
  • 不会触发新一轮 Tick

下面是一个简单的示例,演示了宏任务和微任务的执行顺序:

console.log("Start");

setTimeout(() => {
  console.log("setTimeout");
}, 0);

Promise.resolve().then(() => {
  console.log("Promise");
});

console.log("End");

在这个例子中,代码的执行顺序是:

  1. 打印 ‘Start’
  2. 打印 ‘End’
  3. 执行 Promise 微任务,打印 ‘Promise’
  4. 执行 setTimeout 宏任务,打印 ‘setTimeout’

下面进阶版示例:

console.log("1");

setTimeout(function () {
  console.log("2");
  process.nextTick(function () {
    console.log("3");
  });
  new Promise(function (resolve) {
    console.log("4");
    resolve();
  }).then(function () {
    console.log("5");
  });
});
process.nextTick(function () {
  console.log("6");
});
new Promise(function (resolve) {
  console.log("7");
  resolve();
}).then(function () {
  console.log("8");
});

setTimeout(function () {
  console.log("9");
  process.nextTick(function () {
    console.log("10");
  });
  new Promise(function (resolve) {
    console.log("11");
    resolve();
  }).then(function () {
    console.log("12");
  });
});
  1. 先执行同步任务输出 1
  2. 执行 promise 微任务里的 pending 初始化状态 输出 7
  3. 根据先进先出原则,对 nextTick 的代码输出 6
  4. 执行 promise 微任务 输出 8
  5. 现在执行宏任务,第一个 setTimeout 里有同步任务,输出 2
  6. 继续执行第一个 setTimeout 里微任务 promise 的 pending 初始化状态 输出 4
  7. 先进先出原则,执行微任务 输出 3
  8. 先进先出原则,执行微任务 输出 5
  9. 执行第二个宏任务里的 setTimeout,该宏任务先执行同步任务 输出 9
  10. 继续执行第二个 setTimeout 里微任务 promise 的 pending 初始化状态 输出 11
  11. 先进先出原则,执行微任务 输出 10
  12. 先进先出原则,执行微任务 输出 12

在一个事件循环中,执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

这里容易产生一个错误的认识:就是微任务先于宏任务执行。实际上是先执行同步任务,异步任务有宏任务和微任务两种,先将宏任务添加到宏任务队列中,将宏任务里面的微任务添加到微任务队列中。所有同步执行完之后执行异步,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行。之后就一直循环…
Alt text

h5 自适应方案

在网页开发中,实现 H5 页面的自适应可以让页面在不同设备上展现出更好的效果。以下是一些常用的 H5 自适应方案:

  1. Viewport Meta 标签:Viewport Meta 标签是用来控制页面在移动设备上的视口大小和缩放比例的。通过设置 Viewport Meta 标签,可以让页面根据设备的宽度进行自适应调整。例如:
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
  1. 流式布局:使用百分比或者 em/rem 单位来设置元素的宽度,使得页面元素随着视口大小的改变而自动调整大小。rem 是一种相对长度单位,通常用于前端开发中的样式表(CSS)中。REM 单位是相对于根元素(html 元素)的字体大小(font-size)来计算的。

  2. 媒体查询(Media Queries):通过 CSS3 的媒体查询功能,根据设备的特性(如屏幕宽度、设备类型等)来应用不同的样式。可以针对不同的屏幕尺寸定义不同的样式,从而实现响应式设计。

@media screen and (max-width: 600px) {
  /* 在屏幕宽度小于600px时应用的样式 */
}
  1. Flexbox 布局:使用 Flexbox 布局可以更方便地实现弹性布局,使得页面元素在不同设备上的排列和对齐更加灵活。

前端知识大全地址:https://juejin.cn/post/7270471613547249699

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/414741.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

牛客前端八股文(每日更新)

1.说说HTML语义化&#xff1f; 得分点&#xff1a;语义化标签、利于页面内容结构化、利于无CSS页面可读、利于SEO、利于代码可读 1&#xff0c;标签语义化是指在开发时尽可能使用有语义的标签&#xff0c;比如header&#xff0c;footer&#xff0c;h&#xff0c;p&#xff0c…

Linux学习之system V

目录 一&#xff0c;system V共享内存 快速认识接口 shmget(shared memory get) shmat(shared memory attach) shmdt(shared memory delete) shmctl (shared memory control) 编写代码 综上那么共享内存与管道通信有什么区别&#xff1f; system v消息队列 system v信号…

浅谈 Linux fork 函数

文章目录 前言fork 基本概念代码演示示例1&#xff1a;体会 fork 函数返回值的作用示例2&#xff1a;创建多进程&#xff0c;加深对 fork 函数的理解 前言 本篇介绍 fork 函数。 fork 基本概念 pid_t fork(void) fork 的英文含义是"分叉"&#xff0c;在这里就是 …

web安全学习笔记【15】——信息打点(5)

信息打点-CDN绕过&业务部署&漏洞回链&接口探针&全网扫描&反向邮件 #知识点&#xff1a; 1、业务资产-应用类型分类 2、Web单域名获取-接口查询 3、Web子域名获取-解析枚举 4、Web架构资产-平台指纹识别 ------------------------------------ 1、开源-CMS指…

非线性优化资料整理

做课题看了一些非线性优化的资料&#xff0c;整理一下&#xff0c;以方便查看&#xff1a; 优化的中文博客 数值优化|笔记整理&#xff08;8&#xff09;——带约束优化&#xff1a;引入&#xff0c;梯度投影法 (附代码)QP求解器对比对于MPC的QP求解器 数值优化| 二次规划的…

day02_前后端环境搭建(前端工程搭建,登录功能说明,后端项目搭建)

文章目录 1. 软件开发介绍1.1 软件开发流程1.2 角色分工1.3 软件环境1.4 系统的分类 2. 尚品甄选项目介绍2.1 电商基本概念2.1.1 电商简介2.1.2 电商模式B2BB2CB2B2CC2BC2CO2O 2.2 业务功能介绍2.3 系统架构介绍2.4 前后端分离开发 3. 前端工程搭建3.1 Element-Admin简介3.2 El…

漫漫数学之旅034

文章目录 经典格言数学习题古今评注名人小传 - 大卫希尔伯特 经典格言 研究数学的艺术在于发现包含普遍性萌芽的特殊情形。——大卫希尔伯特&#xff08;David Hilbert&#xff09; 亲爱的朋友&#xff0c;让我们一起进入数学的奇幻世界&#xff0c;那里大卫希尔伯特就像一位智…

LightSNS V1.6.6.0版轻社区解锁版源码优化版

优化&#xff1a;后台面板首页数据统计改成异步加载 优化&#xff1a;同一内容重复评论提示 优化&#xff1a;vip到期个人主页vip专属背景还保留问题 优化&#xff1a;活动报名名额为空可能导致的问题 优化&#xff1a;移动端评论框左下“转发动态”改为“转发内容” 优化&…

【C++】树形关联式容器set、multiset、map和multimap的介绍与使用

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.关联式容器 2.键…

Linux笔记--用户与用户组

Linux系统是一个多用户多任务的操作系统&#xff0c;任何一个要使用系统资源的用户&#xff0c;都必须首先向系统管理员(root)申请一个账号&#xff0c;然后以这个账号的身份进入系统。 用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪&#xff0c;并控制他们对系…

python接口自动化测试 —— unittest框架suite、runner详细使用!

test suite 测试套件&#xff0c;理解成测试用例集一系列的测试用例&#xff0c;或测试套件&#xff0c;理解成测试用例的集合和测试套件的集合当运行测试套件时&#xff0c;则运行里面添加的所有测试用例 test runner 测试运行器用于执行和输出结果的组件 test suite、tes…

【前端素材】推荐优质后台管理系统Salreo平台模板(附源码)

一、需求分析 当我们从多个层次来详细分析后台管理系统时&#xff0c;可以将其功能和定义进一步细分&#xff0c;以便更好地理解其在不同方面的作用和实际运作。 1. 结构层次 在结构层次上&#xff0c;后台管理系统可以分为以下几个部分&#xff1a; a. 辅助功能模块&#…

PostgreSQL:开源巨人的崛起和不可阻挡的发展

PostgreSQL&#xff1a;开源巨人的崛起和不可阻挡的发展 PostgreSQL是一款开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;以其强大的功能和持续的发展势头在数据库领域崭露头角。本文将探讨为什么PostgreSQL的发展势不可挡&#xff0c;从开源精神和强大…

GridView 演示(P28 5.4GridView)

一、目标效果 如下图所示&#xff0c;我们通过 GridView 新建100个子项&#xff0c;每个子项上写有自己的 index。 二、具体实现代码 1. Main.qml import QtQuickWindow {width: 640height: 480visible: truetitle: qsTr("GridView 演示")GridView{anchors.fill…

探索NebulaGraph:一个开源分布式图数据库的技术解析

欢迎关注微信公众号&#xff1a;一休哥助手。多种功能等待你的使用。1. 介绍 NebulaGraph的定位和用途 NebulaGraph是一款开源的分布式图数据库&#xff0c;专注于存储和处理大规模图数据。它的主要定位是为了解决图数据存储和分析的问题&#xff0c;能够处理节点和边数量巨大…

林浩然与杨凌芸的Scala编程历险记:变量与数据类型的魔法对决

林浩然与杨凌芸的Scala编程历险记&#xff1a;变量与数据类型的魔法对决 在Scala世界的梦幻殿堂中&#xff0c;两位英勇的程序员——林浩然和杨凌芸正准备开启一场代码之旅。这次&#xff0c;他们将深入探索Scala王国中的变量奥秘与数据类型丛林。 一、变量声明篇 &#xff0…

【DDD】学习笔记-领域驱动设计体系

从统一语言到限界上下文&#xff0c;从限界上下文到上下文映射&#xff0c;从领域分析建模到领域设计建模&#xff0c;再从领域设计建模到领域实现建模&#xff0c;我将软件架构设计、面向对象设计、场景驱动设计和测试驱动开发有机地融合起来&#xff0c;贯穿于领域驱动设计的…

数据结构:循环队列

一、队列的概念 操作受限的线性表&#xff0c;允许在队列的一端执行入队操作&#xff0c;另一端执行出队操作 先进先出(FIFO) 1.顺序队列 物理结构连续&#xff0c;依赖于数组实现 队列中有一个队头指针和队尾指针&#xff0c;队头指针保存每次要出队的元素&#xff0c;队…

使用Jenkins部署前端Vue项目和后端Java服务

Jenkins安装相关插件&#xff0c;供后续使用&#xff08;Dashboard - Manage Jenkins - Plugins&#xff09; Maven Integration plugin https://plugins.jenkins.io/maven-plugin CloudBees Docker Build and Publish pluginhttps://plugins.jenkins.io/docker-build-publish…

代码随想录算法训练营第64天/最后一天 | 84.柱状图中最大的矩形

今日任务 84.柱状图中最大的矩形 84.柱状图中最大的矩形 - Hard 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾…
最新文章