首页 >> 大全

记录一些web前端面试问题

2023-09-14 大全 28 作者:考证青年

.js的工作原理

首先上一小段代码(index.html),结合代码我们来看看,一步一步都做了些什么。


Hello {{name}}!

当你用浏览器去访问index.html的时候,浏览器依次做了如下一些事情:

加载html,然后解析成DOM;

加载.js脚本;

等待事件的触发

寻找ng-app指令,根据这个指令确定应用程序的边界;

使用ng-app中指定的模块配置 i n j e c t o r ; 使 用 i n j e c t o r 创 建 i n j e c t o r 创 建 c o m p i l e 服 务 和 ; 使用创建创建服务和 ;使用创建创建服务和;

使用服务编译DOM并把它链接到服务编译DOM并把它链接到上;

ng-init指令对scope里面的变量name进行赋值;

表达式{{name}}进行替换,于是乎,显示为“Hello World!”

整个过程可以用这张图来表示:

在这里插入图片描述

好了,通过上面的例子我们清楚了是怎样一步一步渲染出一个页面的。那么它又是如何和浏览器的事件回路来交互的呢?或者说是如何跟用户来交互的呢?粗略来讲,主要分为三个阶段:

1. 浏览器的事件回路一直等待着事件的触发,事件包括用户的交互操作、定时事件或者网络事件(如服务器的响应等);

2. 一旦有事件触发,就会进入到的中,一般通过回调函数来修改DOM;

3. 等到回调函数执行完毕之后,浏览器又根据新的DOM来渲染新的页面。

正如下面一张图所示,交互过程主要由几个循环组成:

在这里插入图片描述

修改了一般的工作流,并且提供了它自己的事件处理机制。这样就把的分隔成两部分,一部分是原生的的,另一部分是的。只有处在的中的操作才能享受到的data-、 、 等服务,但是对于外来者(如原生的操作、自定义的事件回调、第三方的库等)也不是一概不接见,可以使用提供的 a p p l y ( ) 函 数 将 这 些 外 来 者 包 进 A n g u l a r J S 的 c o n t e x t 中 , 让 A n g u l a r 感 知 到 他 们 产 生 的 变 化 。 接 下 来 , 让 我 们 一 起 来 看 看 交 互 过 程 中 的 这 几 个 循 环 是 怎 么 工 作 的 ? 1. 首 先 , 浏 览 器 会 一 直 处 于 监 听 状 态 , 一 旦 有 事 件 被 触 发 , 就 会 被 加 到 一 个 e v e n t q u e u e 中 , e v e n t q u e u e 中 的 事 件 会 一 个 一 个 的 执 行 。

2. e v e n t q u e u e 中 的 事 件 如 果 是 被 apply()函数将这些外来者包进的中,让感知到他们产生的变化。 接下来,让我们一起来看看交互过程中的这几个循环是怎么工作的? 1. 首先,浏览器会一直处于监听状态,一旦有事件被触发,就会被加到一个event queue中,event queue中的事件会一个一个的执行。 2. event queue中的事件如果是被 apply()函数将这些外来者包进的中,让感知到他们产生的变化。接下来,让我们一起来看看交互过程中的这几个循环是怎么工作的?1.首先,浏览器会一直处于监听状态,一旦有事件被触发,就会被加到一个中,中的事件会一个一个的执行。2.中的事件如果是被apply()包起来的话,就会进入到的中,这里的fn()是我们希望在的中执行的函数。

3. 将执行fn()函数,通常情况下,这个函数会改变应用的某些状态。

4. 然后会进入到由两个小循环组成的循环中,一个循环是用来处理循环中,一个循环是用来处理队列(用来一些需要在渲染视图之前处理的操作,通常通过(0)实现,速度会比较慢,可能会出现视图抖动的问题)的,一个循环是处理watch列表(是一些表达式的集合,一旦有改变发生,那么watch列表(是一些表达式的集合,一旦有改变发生,那么watch函数就会被调用)的。循环会一直迭代知道循环会一直迭代知道队列为空并且 w a t c h 列 表 也 为 空 的 时 候 , 即 m o d e l 不 再 有 任 何 变 化 。 5. 一 旦 A n g u l a r J S 的 watch列表也为空的时候,即model不再有任何变化。 5. 一旦的 watch列表也为空的时候,即model不再有任何变化。5.一旦的循环结束,整个执行就会离开和的,紧接着浏览器就会把数据改变后的视图重新渲染出来。

接下来,我们还是结合代码来解析一下:


Hello {{name}}!

这段代码和上一段代码唯一的区别就是有了一个input来接收用户的输入。在用浏览器去访问这个html文件的时候,input上的ng-model指令会给input绑上事件,并且会给name变量建议一个 w a t c h 来 接 收 变 量 值 改 变 的 通 知 。 在 交 互 阶 段 主 要 会 发 生 以 下 一 系 列 事 件 : 1. 当 用 户 按 下 键 盘 上 的 某 一 个 键 的 时 候 ( 比 如 说 A ) , 触 发 i n p u t 上 的 k e y d o w n 事 件 ; 2. i n p u t 上 的 指 令 察 觉 到 i n p u t 里 值 的 变 化 , 调 用 watch来接收变量值改变的通知。在交互阶段主要会发生以下一系列事件: 1. 当用户按下键盘上的某一个键的时候(比如说A),触发input上的事件; 2. input上的指令察觉到input里值的变化,调用 watch来接收变量值改变的通知。在交互阶段主要会发生以下一系列事件:1.当用户按下键盘上的某一个键的时候(比如说A),触发input上的事件;2.input上的指令察觉到input里值的变化,调用apply(“name=‘A’”)更新处于的中的model;

3. 将’A’赋值给name;

4. 循环开始,循环开始,watch列表检测到name值的变化,然后通知{{name}}表达式,更新DOM;

5. 退出的,然后退出的中的事件;

6. 浏览器重新渲染视图。

vue的底层实现原理

这是一段典型的体现了Vue特点的代码:

{{word}}

//点击这个button,word的值会发生改变

Vue实现这种数据双向绑定的效果,需要三大模块:

:能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅

:对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数

:作为连接和的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

web前端面试自我介绍_百度web前端笔试面试题目_

的核心是通过.()来监听数据的变动,这个函数内部可以定义和,每当数据发生变化,就会触发。这时候就要通知订阅者,订阅者就是。

订阅者作为和之间通信的桥梁,主要做的事情是:

在自身实例化时往属性订阅器(dep)里面添加自己

自身必须有一个()方法

待属性变动dep.()通知时,能调用自身的()方法,并触发中绑定的回调

主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。

几种实现双向绑定的做法

目前几种主流的mvc(vm)框架都实现了单向数据绑定,而我所理解的双向数据绑定无非就是在单向绑定的基础上给可输入元素(input、等)添加了(input)事件,来动态修改model和 view,并没有多高深。所以无需太过介怀是实现的单向或双向绑定。

实现数据绑定的做法有大致如下几种:

发布者-订阅者模式(.js)

脏值检查(.js)

数据劫持(vue.js)

发布者-订阅者模式: 一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set(‘’, value),这里有篇文章讲的比较详细,有兴趣可点这里

这种方式现在毕竟太low了,我们更希望通过 vm. = value 这种方式更新数据,同时自动更新视图,于是有了下面两种方式

脏值检查: .js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 () 定时轮询检测数据变动,当然不会这么low,只有在指定的事件触发时进入脏值检测,大致如下:

DOM事件,譬如用户输入文本,点击按钮等。( ng-click )

XHR响应事件 ( $http )

浏览器变更事件 ( $ )

Timer事件( $ , $ )

执行 $() 或 $apply()

数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过.()来劫持各个属性的,,在数据变动时发布消息给订阅者,触发相应的监听回调。

vue的生命周期

如何理解的脏检查?

脏检查是一种模型到视图的数据映射机制,由 $apply 或 $ 触发。

脏检查的范围是整个页面,不受区域或组件划分影响

使用尽量简单的绑定表达式提升脏检查执行速度

尽量减少页面上绑定表达式的个数(单次绑定和ng-if)

给 ng- 添加 track by 让 复用已有元素

比如有如下代码:

用户点击了 , 执行了一个叫 的方法。这个 的方法体对于 来说是黑盒,它到底做了什么不知道。可能改了 $scope. 的值,可能改了 $scope. 的值,也可能两个值都改了,也可能都没改。

那么 到底应该怎样得知 () 这段代码后是否应该刷新 UI,应该更新哪个 DOM 元素?

必须去挨个检查这些元素对应绑定表达式的值是否有被改变。这就是脏数据检查的由来(脏数据检查以下简称脏检查)。

脏检查如何被触发?

_web前端面试自我介绍_百度web前端笔试面试题目

会在可能触发 UI 变更的时候进行脏检查。实际上,脏检查是 d i g e s t 执 行 的 , 另 一 个 更 常 用 于 触 发 脏 检 查 的 函 数 执行的,另一个更常用于触发脏检查的函数 执行的,另一个更常用于触发脏检查的函数apply其实就是$的一个简单封装。

通常写代码时我们无需主动调用 $apply 或 $ 是因为 在外部对我们的回调函数做了包装。例如常用的 ng-click,这是一个指令(),内部实现则 类似于

 DOM.addEventListener('click', function ($scope) {$scope.$apply(() => userCode());});

可以看到:ng-click 帮我们做了 $apply 这个操作。类似的不只是这些事件回调函数,还有 h t t p 、 http、 http、 等。我听很多人抱怨说 这个库太大了什么都管,其实你可以不用它自带的这些服务(),只要你记得手工调用 s c o p e . scope. scope.apply。

脏检查的范围

前面说到: 会对所有绑定到 UI 上的表达式做脏检查。其实,在 实现内部,所有绑定表达式都被转换为 s c o p e . scope. scope.watch()。每个 $watch 记录了上一次表达式的值。有 ng-bind=“a” 即有 s c o p e . scope. scope.watch(‘a’, ),而 s c o p e . scope. scope.watch 可不会管被 watch的表达式是否跟触发脏检查的事件有关。

问:点击 TEST 这个按钮时会触发脏检查吗?触发几次?

首先:ng-click="" 什么都没有做。 会因为这个事件回调函数什么都没做就不进行脏检查吗?不会。

然后:#span1 被隐藏掉了,会检查绑定在它上面的表达式吗?尽管用户看不到,但是 s c o p e . scope. scope.watch(‘’, ) 还在。就算你直接把这个 span 元素干掉,只要 watch 表达式还在,要检查的还会检查。

再次:重复的表达式会重复检查吗?会。

最后:别忘了 ng-show=“false”。可能是因为 的开发人员认为这种绑定常量的情况并不多见,所以 $watch 并没有识别所监视的表达式是否是常量。常量依旧会重复检查。

所以:

答:触发三次。一次 false,一次 ,一次

所以说一个绑定表达式只要放在当前 DOM 树里就会被监视,不管它是否可见,不管它是否被放在另一个 Tab 里,更不管它是否与用户操作相关。

另外,就算在不同 里构造的 $scope 也会互相影响,别忘了 还有全局的 $,你还可以 s c o p e . scope. scope.emit。 无法保证你绝对不会在一个 里更改另一个 生成的 scope,包括 自定义指令()生成的 scope 和 1.5 里新引入的组件()。

所以说不要怀疑用户在输入表单时 会不会监听页面左边导航栏的变化。

页面的重绘与回流及优化

首先要清楚页面呈现的具体过程:

浏览器把获取到的HTML代码解析成1个DOM树,HTML中的每个tag都是DOM树中的1个节点,根节点就是我们常用的对象。DOM树里包含了所有HTML标签,包括:none隐藏,还有用JS动态添加的元素等。

浏览器把所有样式(用户定义的CSS和用户代理)解析成样式结构体,在解析的过程中会去掉浏览器不能识别的样式,比如IE会去掉-moz开头的样式,而FF会去掉_开头的样式。

3、DOM Tree 和样式结构体组合后构建 tree, tree类似于DOM tree,但区别很大, tree能识别样式, tree中每个NODE都有自己的style,而且 tree不包含隐藏的节点 (比如:none的节点,还有head节点),因为这些节点不会用于呈现,而且不会影响呈现的,所以就不会包含到 tree中。注意 :隐藏的元素还是会包含到 tree中的,因为: 会影响布局(),会占有空间。根据CSS2的标准, tree中的每个节点都称为Box (Box ),理解页面元素为一个具有填充、边距、边框和位置的盒子。

3. 一旦 tree构建完毕后,浏览器就可以根据 tree来绘制页面了。如下图:

在这里插入图片描述

回流与重绘

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

当 tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如-color。则就叫称为重绘。

注意:回流必将引起重绘,而重绘不一定会引起回流。 我们需要明白,页面若发生回流则需要付出很高的代价。

回流何时发生:

当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流:

1、添加或者删除可见的DOM元素;

2、元素位置改变;

3、元素尺寸改变——边距、填充、边框、宽度和高度

4、内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;

5、页面渲染初始化;

6、浏览器窗口尺寸改变——事件发生时;

从一个无限大数组里面筛选出前5个数字最大的

先sort()排序,然后()大小颠倒。最后slice(0,6)取出最大的5个值

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了