介绍下重绘和回流(Repaint & Reflow),以及如何进行优化
个人题解
浏览器渲染主要经过三个阶段
1、dom树与style树合成渲染树
2、计算节点的位置与大小的阶段叫回流
3、渲染计算好的节点叫重绘
如何优化
1、减少dom插入次数,可以用虚拟的节点,计算好以后,一次性插入到dom中
2、动画可以使用绝对布局,脱离文档流
3、使用gpu加速相关的属性,比如transition
4、修改的节点可以先隐藏,修改完毕后再进行显示.
1、Object.prototype.toString.call(),是使用原型上的toString()方法,输出为[Object xxxxx],通过xxxxx的内容判断当前的类型.目前大部分判断类型都是基于此方法,比较准确
1 | console.log(Object.prototype.toString.call([1, 2, 3])); //[object Array] |
2、instanceof是基于原型链的判断方法,一个数组会找到他的原型是不是属于array,如果是返回true
1 | let fsimpleStr = "This is a simple string"; |
3、Array.isArray(),Array对象上提供的判断是否是数组的方法,比较准确
1 | Array.isArray([1, 2, 3]); |
第 21 题:有以下 3 个判断数组的方法,请分别介绍它们之间的区别和优劣Object.prototype.toString.call() 、 instanceof 以及 Array.isArray()
MDN isArray
MDN instanceof
不会
在 HTTP/1 中,每次请求都会建立一次HTTP连接,也就是我们常说的3次握手4次挥手,这个过程在一次请求过程中占用了相当长的时间,即使开启了 Keep-Alive ,解决了多次连接的问题,但是依然有两个效率上的问题:
第一个:串行的文件传输。当请求a文件时,b文件只能等待,等待a连接到服务器、服务器处理文件、服务器返回文件,这三个步骤。我们假设这三步用时都是1秒,那么a文件用时为3秒,b文件传输完成用时为6秒,依此类推。(注:此项计算有一个前提条件,就是浏览器和服务器是单通道传输)
第二个:连接数过多。我们假设Apache设置了最大并发数为300,因为浏览器限制,浏览器发起的最大请求数为6,也就是服务器能承载的最高并发为50,当第51个人访问时,就需要等待前面某个请求处理完成。
HTTP/2的多路复用就是为了解决上述的两个性能问题。
在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream)。
帧代表着最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。
多路复用,就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。
不会
第 15 题:简单讲解一下 http2 的多路复用 #14
http1.1 与 http2 对比
HTTP/2 相比 1.0 有哪些重大改进?
HTTP/2 资料汇总
1 | function Demo(a, b) { |
1 | function _new(fn, ...arg) { |
Object.create(fn.prototye)创建原型对象1 | function fibonacci(n) { |
1 | function fibonacci(n, cache) { |
1 | function fibonacci(n) { |
一开始底牌尽处的人,注定是输家.
最开始使用的是callback,比如浏览器端的dom事件,ajax.node上的io事件等等,但是有定位问题困难,callback hell,异常处理等问题
1 | // 浏览器端 |
相比callback的回调写法,链式调用的写法更优雅,异常处理变得友好.
1 | const demo = function () { |
用的不多,不做评价.emmm 打扰了
异步终极解决方案,generator/yield语法糖,基于promise,同步的写法,同步代码的异常捕获能力.强!无敌!
1 | const demo = function () { |
JS 异步已经告一段落了,这里来一波小总结
setTimeout(() => {
// callback 函数体
}, 1000)
缺点:回调地狱,不能用 try catch 捕获错误,不能 return
回调地狱的根本问题在于:
1 | ajax('XXX1', () => { |
Promise就是为了解决callback的问题而产生的。
Promise 实现了链式调用,也就是说每次 then 后返回的都是一个全新 Promise,如果我们在 then 中 return ,return 的结果会被 Promise.resolve() 包装
优点:解决了回调地狱的问题
1 | ajax('XXX1') |
缺点:无法取消 Promise ,错误需要通过回调函数来捕获
特点:可以控制函数的执行,可以配合 co 函数库使用
1 | function *fetch() { |
let a = 0
let b = async () => {
a = a + await 10
console.log('2', a) // -> '2' 10
}
b()
a++
console.log('1', a) // -> '1' 1
对于以上代码你可能会有疑惑,让我来解释下原因
首先函数 b 先执行,在执行到 await 10 之前变量 a 还是 0,因为 await 内部实现了 generator ,generator 会保留堆栈中东西,所以这时候 a = 0 被保存了下来
因为 await 是异步操作,后来的表达式不返回 Promise 的话,就会包装成 Promise.reslove(返回值),然后会去执行函数外的同步代码
同步代码执行完毕后开始执行异步代码,将保存下来的值拿出来使用,这时候 a = 0 + 10
上述解释中提到了 await 内部实现了 generator,其实 await 就是 generator 加上 Promise的语法糖,且内部实现了自动执行 generator。如果你熟悉 co 的话,其实自己就可以实现这样的语法糖。
本文首发于我的博客:JS异步解决方案的发展历程以及优缺点
文章链接
最高赞作者github
最高赞作者地址 JS异步解决方案的发展历程以及优缺点
阮一峰 Javascript异步编程的4种方法