【前端知识点】

news2024/11/19 15:35:46

虚拟 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.coloradmin.cn/o/1475663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

雾锁王国服务器怎么建?雾锁王国服务器搭建方法

雾锁王国Enshrouded服务器搭建怎么搭建&#xff1f;非常简单&#xff0c;阿里云计算巢雾锁王国程序&#xff0c;可以一键搭建雾锁王国多人联机服务器&#xff0c;腾讯云是基于雾锁王国镜像系统&#xff0c;阿里云服务网aliyunfuwuqi.com汇总雾锁王国服务器搭建&#xff0c;超简…

Python爬虫实战第二例【二】

零.前言&#xff1a; 本文章借鉴&#xff1a;Python爬虫实战&#xff08;五&#xff09;&#xff1a;根据关键字爬取某度图片批量下载到本地&#xff08;附上完整源码&#xff09;_python爬虫下载图片-CSDN博客 大佬的文章里面有API的获取&#xff0c;在这里我就不赘述了。 一…

早产儿视网膜病变分期,自动化+半监督(无需大量医生标注数据)

早产儿视网膜病变 ROP 分期 提出背景解法框架解法步骤一致性正则化算法构建思路 实验 提出背景 论文&#xff1a;https://www.cell.com/action/showPdf?piiS2589-0042%2823%2902593-2 早产儿视网膜病变&#xff08;ROP&#xff09;目前是全球婴儿失明的主要原因之一。 这是…

链表基础知识详解(非常详细简单易懂)

概述&#xff1a; 链表作为 C 语言中一种基础的数据结构&#xff0c;在平时写程序的时候用的并不多&#xff0c;但在操作系统里面使用的非常多。不管是RTOS还是Linux等使用非常广泛&#xff0c;所以必须要搞懂链表&#xff0c;链表分为单向链表和双向链表&#xff0c;单向链表很…

求两个向量之间的夹角

求两个向量之间的夹角 介绍Unity的API求向量夹角Vector3.AngleVector3.SignedAngle 自定义获取方法0-360度的夹角 总结 介绍 求两个向量之间的夹角方法有很多&#xff0c;比如说Unity中的Vector3.Angle&#xff0c;Vector3.SignedAngle等方法&#xff0c;具体在什么情况下使用…

Groovy(第九节) Groovy 之单元测试

JUnit 利用 Java 对 Song 类进行单元测试 默认情况下 Groovy 编译的类属性是私有的,所以不能直接在 Java 中访问它们,必须像下面这样使用 setter: 编写这个测试用例余下的代码就是小菜一碟了。测试用例很好地演示了这样一点:用 Groovy 所做的一切都可以轻易地在 Java 程序…

使用 gregwar/captcha 生成固定字符的验证码

图片验证码生成失败 $captcha new CaptchaBuilder("58 ?"); $code $captcha->getPhrase();\Cache::put($key, [phone > $phone, code > $captcha->getPhrase()], $expiredAt);$captcha->build(); $result [captcha_key > $key,expired_at >…

Linux------进程地址空间

目录 一、进程地址空间 二、地址空间本质 三、什么是区域划分 四、为什么要有地址空间 1.让进程以统一的视角看到内存 2.进程访问内存的安全检查 3.将进程管理与内存管理进行解耦 一、进程地址空间 在我们学习C/C的时候&#xff0c;一定经常听到数据存放在堆区、栈区、…

雾锁王国服务器官方配置要求说明

雾锁王国/Enshrouded服务器CPU内存配置如何选择&#xff1f;阿里云服务器网aliyunfuwuqi.com建议选择8核32G配置&#xff0c;支持4人玩家畅玩&#xff0c;自带10M公网带宽&#xff0c;1个月90元&#xff0c;3个月271元&#xff0c;幻兽帕鲁服务器申请页面 https://t.aliyun.com…

TCP/IP-常用网络协议自定义结构体

1、TCP/IP模型&#xff1a; 2、TCP/IP- 各层级网络协议&#xff08;从下往上&#xff09;&#xff1a; 1&#xff09;数据链路层&#xff1a; ARP: 地址解析协议&#xff0c;用IP地址获取MAC地址的协议&#xff0c;通过ip的地址获取mac地 …

Vue项目 快速上手(如何新建Vue项目,启动Vue项目,Vue的生命周期,Vue的常用指令)

目录 一.什么Vue框架 二.如何新建一个Vue项目 1.使用命令行新建Vue项目 2.使用图形化界面新建Vue项目 三.Vue项目的启动 启动Vue项目 1.通过VScode提供的图形化界面启动Vue项目 2.通过命令行的方式启动Vue项目 四.Vue项目的基础使用 常用指令 v-bind 和 v-model v…

学生党福音!趁着拍拍开学季活动买平板啦!

谁还在买5年前的平板啊&#xff1f; 当然是我&#xff01; 虽然手里有台ipad&#xff0c;但ios系统限制多&#xff0c;不方便&#xff0c;一直想再要一台安卓平板。 去年观望了好久小米平板5pro&#xff0c;想着如果8256G配置价格在1500以下就入手&#xff0c;结果一直不掉价…

4_怎么看原理图之协议类接口之SPI笔记

SPI&#xff08;Serial Peripheral Interface&#xff09;是一种同步串行通信协议&#xff0c;通常用于在芯片之间传输数据。SPI协议使用四根线进行通信&#xff1a;主设备发送数据&#xff08;MOSI&#xff09;&#xff0c;从设备发送数据&#xff08;MISO&#xff09;&#x…

苹果ios群控软件开发常用源代码分享!

在移动软件开发领域&#xff0c;苹果设备由于其封闭性和安全性受到了广大开发者的青睐&#xff0c;然而&#xff0c;这也为开发者带来了一些挑战&#xff0c;特别是在进行群控软件开发时。 群控软件是指可以同时控制多台设备的软件&#xff0c;这在自动化测试、批量操作等场景…

01 MySQL之连接

1. 连接 1.0 基础认知 多表(主表)和一表(从表的区别): 多表一般是主表&#xff0c;一般存储主要数据&#xff0c;每个字段都可能存在重复值&#xff0c;没有主键&#xff0c;无法根据某个字段定位到准确的记录&#xff1b; 一表一般是从表&#xff0c;一般存储辅助数据&…

『Java安全』编译jdk

文章目录 一、源码下载二、环境依赖配置[^1]三、依赖检查及构建编译配置四、编译jdk五、编译完成完 一、源码下载 以OpenJDK为例&#xff1a; jdk&#xff1c;10访问OpenJDK Mercurial Repositories jdk≥10访问子目录jdk/jdk12: log (openjdk.org) 二、环境依赖配置1 i7-…

神经网络结构搜索(NAS)

华为诺亚AI系统工程实验室主任刘文志解读如何使用AutoML预测基站流量 - 知乎讲师介绍&#xff1a;刘文志&#xff08;花名风辰&#xff09;&#xff0c;华为诺亚AI系统工程实验室主任&#xff0c;异构并行计算专家&#xff0c;毕业于中国科学院研究生院&#xff0c;闻名于并行计…

鸿蒙应用程序包安装和卸载流程

开发者 开发者可以通过调试命令进行应用的安装和卸载&#xff0c;可参考多HAP的调试流程。 图1 应用程序包安装和卸载流程&#xff08;开发者&#xff09; 多HAP的开发调试与发布部署流程 多HAP的开发调试与发布部署流程如下图所示。 图1 多HAP的开发调试与发布部署流程 …

全网最详细的接口自动化测试框架实战(Pytest+Allure+Excel)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1. Allure 简介 Allure 框架是一个灵活的、轻量级的、支持多语…

Flink动态分区裁剪

1 原理 1.1 静态分区裁剪与动态分区裁剪 静态分区裁剪的原理跟谓词下推是一致的&#xff0c;只是适用的是分区表&#xff0c;通过将where条件中的分区条件下推到数据源达到减少分区扫描的目的   动态分区裁剪应用于Join场景&#xff0c;这种场景下&#xff0c;分区条件在joi…