react 基本概念解析
关于 react 你必须要知道的事情~
操作 Dom 的成本很高 不要轻易去操作 Dom 这句话从开始入门就听说,那么这里说的成本是指什么?
由此引出今天的问题
首先我们要清楚几个概念
讨论 DOM 操作成本 首先要了解下该成本的来源 那么就离不开浏览器渲染
浏览器渲染前需要先构建 DOM 和 CSS 树 因此我们需要尽快将 HTML 和 CSS 都提供给浏览器
这里只讨论浏览器拿到 HTML 之后开始解析 渲染
之前的一些另开一篇
每个浏览器都有自己的默认样式表因此很多时候这颗 CSSOM 树只是对这张默认样式表的部分替换
DOM 和 CSSOM 都要经过Bytes→characters→tokens→nodes→objectmodel
这个过程
DOM 和 CSSOM 是独立的数据结构
此处需要一张图片
1 | 在dom树中每一个需要显示的节点在渲染树种至少存在一个对应的节点 渲染树中的节点被称之为“帧”或者“盒” 符合css模型的定义 一旦Dom树和渲染树构建完成 浏览器就开始 显示(绘制paint)页面元素 |
简单描述下 render 的过程
1 | DOM树从根节点开始遍历可见节点 |
1 | Layout布局 |
1 | Paint绘制 |
TIPS:
reflow (重排):当 dom 树的变化影响了元素的集合属性 =》 意味着元素的内容,结构 位置或者尺寸发生了变化,同样其他元素的集合属性和位置也会因此受到影响,浏览器会使渲染树(render 树)中受到影响的部分失效 需要重新计算样式和渲染树,这个过程称为重排(reflow)
repaint (重绘): 意味着元素发生的改变只你影响了节点的一些样式(背景色 边框颜色 文字元素等)只需要应用新样式绘制这个元素就可以了 (完成重排后 浏览器会重新绘制受影响的部分到屏幕中 这个过程叫做重绘)
并不是所有的 dom 辩护都会影响几何属性 例如 改变元素的背景色不会影响 宽和高 这种情况下 只会发生一次重绘(不需要重排)因为元素的布局没有改变
重排一定会引起浏览器的重绘 重绘则不一定伴随重排
重排的成本开销要高于重绘一个节点的重排往往导致子节点以及同级节点的重排
当页面布局的几何属性改变时就需要重排 下列情况会导致重排
1 | 页面第一次渲染(初始化) |
由于每次重排都会产生计算消耗,大多数浏览器通过队列化修改并批量执行来优化重排的过程
但是 我们经常会不知不觉强制刷新队列并要求计划任务立即执行
获取布局信息的操作会到最后队列刷新 比如
1 | offsetTop , offsetLeft , offsetWidth , offsetHeight |
当获取以上的属性和方法时 浏览器为了获取最新的布局信息 不得不立即触发重排以返回正确的值
重绘和重排代价很昂贵 因此一个号的提高程序响应熟读的策略就是减少此类操作的发生
1 | 思考 |
* 使元素脱离文本流
* 操作元素
* 操作完成后 将元素带回文档中
这样儿 只有第一步和第三部触发两次重排
有三种方式可以实现上面的步骤
1. 隐藏元素(display:none)操作元素 重新展示
1 | var ul = document.getElementById('mylist'); |
2. 使用文档片段(document fragment)在当前 DOM 之外构建一个子树,再把它拷贝回文档
1 | var fragment = document.createDocumentFragment(); |
3. 将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换原始元素
1 | var old = document.getElementById('mylist'); |
总结:推荐尽可能的使用文档片段(第二个方案),因为它们所产生的 DOM 遍历和重排次数最少。唯一潜在的问题是文档片段未被充分利用,很多人可能并不熟悉这项技术。
1 | 浏览器获取元素的offsetLeft等属性值时会导致重排 将需要获取的保护局信息的属性值 赋值给变量 然后再操作变量 |
1 | 将需要多次重排的元素,position 属性设置为 absolute 或 fixed,这样元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。 |
操作 DOM 具体的成本,说到底是造成浏览器重排和重绘,从而消耗 GPU 资源
s
针对不同的请求,Express 提供了 use 方法的一些别名。比如,上面代码也可以用别名的形式来写。
1 | var express = require("express"); |
除了 get 方法以外,Express 还提供 post、put、delete 方法,即 HTTP 动词都是 Express 的方法,express 允许模式匹配
用于指定变量的值
1 | app.set('views',_dirname+'/views') |
response.redirect () 允许网址的重定向response.redirect("/hello/anime");
response.sendFile () 用于发送文件response.sendFile("/path/to/anime.mp4")
response.render () 用于渲染网页模版
1 | app.get("/", function(request, response) { |
使用 render 方法,将 message 变量传入 index 模版,渲染成 HTML 网页
request.ip: 用于获取 HTTP 请求的 IP 地址
request.files 用于获取上传的文件
使用 express 搭建 https 加密服务器
1 | var fs = require('fs'); |
1 | 当我们在浏览器地址输入url时,浏览器会发送请求到服务器,服务器将请求的html文档发送回浏览器,浏览器将文档下载下来后 便开始从上到下解析,解析完成后 会生成dom,如果页面中有css 会根据css的内容 形成cssdom 然后 dom和css会生成一个渲染树 最后浏览器会根据渲染树的内容计算出各个节点在页面中的确切大小和位置,并将其绘制在浏览器上 |
1 | 在解析html的过程中 有时候解析会被中断,这是因为javascript会阻塞dom的解析 当解析过程中遇到script标签的时候 便会停止解析过程 抓转而去处理脚本 如果脚本是内联的 浏览器会先去执行这段内联的脚本,如果脚本是外链的 那么先去加载脚本 然后执行 在处理完脚本之后 浏览器便继续解析html文档 |
当文档中没有脚本时 浏览器解析完成文档便能触发 DomContentLoaded 事件 如果文档包含脚本 则脚本会阻塞文档的解析 而脚本需要等位于前面的 css 加载完才能执行 在任何情况下 DomContentLoaded 的触发不需要等待图片等其他资源加载完成
1 | DOMContentLoaded不同的浏览器对其支持不同,所以在实现的时候我们需要做不同浏览器的兼容。 |
页面上所有的资源(图片,音频,视频等)被加载以后才会触发 load 事件,简单来说,页面的 load 事件会在 DOMContentLoaded 被触发之后才触发。
1 | window.onload = function(){ |
因为浏览器生成 Dom 树的时候是一行一行读 html 代码的 script 标签放在最后面就不会影响前面的页面渲染,那么问题来了
既然 Dom 树完全生成好页面才能渲染出来 浏览器又必须读完全部的 html 才能生成完成的 dom 树 script 标签放不放在底部是不是也一样 因为 dom 树的生成需要整个文档解析完成
chrome 页面渲染过程中 会有 firstpaint 的概念,现代浏览器为了更好的用户体验,渲染引擎将尝试尽快在屏幕上显示的内容 他不会等到所有的 html 解析完成才开始构建和布局 dom 树 部分的内容被解析并展示 也就是说 浏览器能够渲染不完整的 dom 树和 cssdom 尽快的减少白屏时间
假如我们将 js 放在 header js 将会阻塞解析 dom dom 的内容会影响到 firstpaint 导致 firstpaint 延后 所以说我们会将 js 放在后面 以减少 firstpaint 时间但是不会减少 DomContentLoaded 被触发的时间
去除 input [type=’number’] 时的右侧上下箭头
/ 在 chrome 下:/
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button{
-webkit-appearance: none !important;
margin: 0;
padding-left:5px;
}
/*Firefox下:*/
input[type="number"]{-moz-appearance:textfield;}
判断小数不能大于两位
var hopePriceLength = hopePrice.toString().split(".")[1].length;
if(hopePriceLength>2){
notify('请输入正数,最多两位小数','error');
$(`#${mid}jp-hope-price`).focus();
return false;
}
近期在研究异步编程的我对于 setTimeout 之类的东西异常敏感。在 SegmentFault 上看到了一个问题《关于 SetTimeout 时间设为 0 时》:提问者读了一篇文章,原文解释 setTimeout 延迟时间为 0 时会发生的事情,提问者提出了几个文章中的几个疑点。读了那篇文章之后发现原文的作者对于 setTimeout 的理解和自己的认知有点出入,于是编写了相关测试的代码以求答案。最终编写了这篇文章。
本文内容如下:
起因
单线程的 JavaScript
setTimeout 背后意味着什么
不同于传统面向对象语言中的类式继承 js 通过 原型委托 的方式实现对象与对象之间的继承
编程语言分为 :
静态类型语言:编译时已确定变量的类型
优点:在编译时就能发现类型不匹配的错误,编译器可以针对不同的数据类型对程序做一些优化工作 提高程序之心速度
缺点:程序员依照契约来编写程序
动态类型语言:要到程序运行的时候 待变量被赋予某个值之后 才会具有某种类型
优点:代码数量少
缺点:程序在运行期间有可能发生跟类型相关的错误
Javascript 是一门典型的动态类型语言
多态:给不同的对象发送同一条消息的时候 这些对象会根据这个消息分别给出不同的反馈
多态:
多种形态 在面向对象语言中,接口的多种不同的实现方式即为多态
多态指同一个实体同时具有多种形式
思想:把做什么 和 谁去做 分开
同一个函数 传入不同的参数 可以实现不同的结果
js 的多态是与生俱来的
它作为一门动态类型语言 他在编译时没有类型检查的类型
多态的好处:你不必再向对象询问‘你是什么类型’而后根据得到的答案 调用对象的某个行为 你只管调用该行为就是了
最根本的作用就是通过把过程话的条件分支语句转化为对象的多态性 从而消除这些条件分支语句
面向对象编程的优点
将行为分布在各个对象中,并且让这些对象各自负责自己的行为
当我们对一些函数发出 调用的指令时 这些函数会返回不同的结果
这也是多态的一些体现
封装:封装的目的是将信息隐藏
封装数据
封装实现
封装类型
封装变化
把系统中不变的和变的分离开 只替换变化的 如果变化的也是封装好的 就好替换多了 保证程序的稳定性和可扩展性
隐藏数据 隐藏实现细节 设计细节以及隐藏对象的类型
其他对象或者用户不关心他的具体实现 封装使对象之前的耦合变得松散 对象之间只暴露 APi 接口来通信
1 | var Plane = function(){ |
最近尝试了解了一些移动端的概念
得空总结了网易与淘宝的一些适配方案,为后续工作记录一下