前端知识理解的笔记
html语义化的作用
- 根据内容的结构使用适当的标签,便于开发者阅读和代码的结构优雅
- 语义化标签会让网络爬虫和机器更好的解析页面,从而暴露给爬虫更多的有效数据。有利于seo
- 语义化标签提高用户体验,比如title和alt属性,label标签的表单控制
- 方便其他设备解析渲染网页,屏幕阅读器
- 便于维护和开发。
react的diff算法理解
react利用虚拟dom和diff算法,进行新dom和旧dom的差异计算,再进行对应dom片段的真实dom更新,其算法有三个级别:tree(树)、component(组件)、element(元素),性能依次增强。
- tree级别的diff算法,顾名思义,对一棵树进行diff算法,react必须检索整棵树,然后计算出差异片段,react利用先添加后删除的实现方法,更新整个dom,tree级别的diff影响性能,因此我们尽量避免在页面上有dom树层面的改动
- component级别的diff算法,react的dom片段单位就是组件,定义一个class,就是定义了一个虚拟dom组件。组件进行diff算法,如果新的dom与旧的dom的组件不是同一个class,那么react认为其无法复用,直接删除旧组件,添加新的组件。因为我们定义的每一个class都有不同的dom结构,react不需要去检索dom结构。
- element级别的diff算法,element级别的算法,同一等级的元素需要有唯一的key进行关联,让react可以新旧dom进行匹配。此级别中,react有三种行为:
- 新的element不存在于旧dom中,插入新element
- 旧element不存在新dom中,删除旧element
- 新element存在旧dom,顺序发生改变,则进行移动dom
在dom更新时,react会遍历一遍新的dom判断与旧dom的差异,diff算法的巧妙就在于,如果element只是位置发生了变化,如果进行删除增加的方法,影响性能。所 以react制定了一个规则去将旧dom排序。
排序规则如下: 如果element在旧dom中的位置比新dom中的位置小,就将element右移,如果element在旧dom中的位置比新dom中的位置一样或者大,不改变它 的位置, react只需要改动前者,就会将位置差异的dom排列完成。
比如一个dom列表为 A B C D , 将要渲染的dom列表变成了 B A D C , react会将B右移, D右移。从不会将A、C左移的操作。
react中的key的重要作用
在遍历插入组件时,我们常会设置一个key值给组件,这便是react的diff算法时需要的key,如果没有了这个key值,react没法进行新dom与旧dom中element的匹配,从而没法进行判断element是否只是位置发生了变化,因此只能进行删除和插入的操作,对dom的删除插入,因此降低性能。
vue和angular的双向数据绑定的实现
1. angular的双向数据绑定 - 脏检查机制
angular的$scope挂在了所有的双向数据绑定的属性,在页面渲染完毕后,angular会将所有的可能改变数据模式的行为进行监听,如事件、ajax请求、timeout等。一旦有这些行为需要触发,angular在每一个行为完成后都会进行$digist循环,来进行脏值检查,如果有新的值,那么angular就发布更新,使得响应到视图。
由于这个特性,因此我们用原生js或者jqeury等外部的行为改变数据模型的值,angular并无法检测,因此无法进入脏值检查阶段,这时候我们就需要$apply方法手动进入$digist循环,它会检查所有监听的内容。
2. vue的双向数据绑定 - 数据劫持
vue的双向数据绑定离不开Object.defineProperty方法,此方法无法兼容ie9以前,因此vue不兼容老版本ie浏览器。
vue在实例化过程中,保存了所有data中的属性,并且给每一个属性定义监听器,在定义监听器同时,会创建一个发布器,该发布器会添加订阅者到该属性下,当某一时刻,数据模型发生了改变,该发布器会触发响应,通知所有订阅者引起更新,通过订阅/发布模式来进行交互。
Promise的语法笔记
Promise纳入了es6标准之前,angular、jquery等的类Promise的实现,并非标准的 Promise,这里记录一下Promise的标准语法
1. Promise对象
var p = new Promise(function (resolve, reject) { setTimeout(function () { var ra = Math.random() ra < 0.5 ? resolve() : reject() }, 1000) }) p.then(function () { console.log('成功') }, function () { console.log('失败') })
new Promise() 构造函数建立一个Promise对象
其最常见的就是then方法,then方法可接收3个函数,一般传递2个,最常见传递1个。
分别为 成功回调、失败回调、完成回调
如果只想定义失败回调可以这样定义
var p = new Promise(function (resolve, reject) { // ... }) p.then(null, function () { console.log('失败') })
promise对象还有一个方法是catch,捕捉异常。利用这个方法改进上面方法
var p = new Promise(function (resolve, reject) { // ... }) p.catch(function (err) { console.log('失败') })
catch来处理所有的失败情况。
then方法可以多个调用,return不会终止then方法继续调用,如果需要终止then方法的往下执行,throw抛出异常。
var p = new Promise(function (resolve, reject) { // ... }) p.then(function () { console.log('第一次then') // 未成功阻止 return false }).then(function (falg) { console.log('第二次then, falg = ' + flag) // false throw new Error('终止') }).then(function (){ console.log('执行不到') }).catch(function () { console.log('失败') })
then方法中所有的return值都会传递给下一个then,就像一个加工流水线,一个一个往下传。一个then中执行一类操作。
2. 返回新的Promise对象
then方法中可以返回新的promise对象
p.then(function (res) { console.log('第一个Promise') // 未成功阻止 return new Promise(function () { // ... }) }).then(function (res) { console.log('第二个Promise对象') }).catch(function () { console.log('失败') })
第一个then中return的Promise内,resolve的值会传递给第二个then的res参数。
3. Promise.all 并行执行所有promise对象
var arr = [] arr[0] = new Promise(function (resolve, reject) { // ... }) arr[1] = new Promise(function (resolve, reject) { // ... }) Promise.all(arr).then(function (resArr) { // .. }).catch(function (err) { // .. })
执行所有Promise对象,resArr保存着相对应的结果
4. Promise.resolve()
Promise.resolve().then(function () { console.log('开始') }).catch(function (err) { // .. }) console.log('最后') // 最后 // 开始
Promise.resolve方法直接返回一个发布成功的Promise,此方法用来将then方法延迟,如上。then方法会延迟到当前函数栈调用的最后,因此改变了console.log的顺序