key帮助React识别哪些项目已更改,已添加或已删除。也所以能够高效的更新虚拟DOM列表,key值是用来判断 VDOM 元素项的惟一依据css
在React中,若是是由React引起的事件处理(好比经过onClick引起的事件处理)或者钩子函数中,调用setState不会同步更新this.state,除此以外的setState调用会同步执行this.state。所谓“除此以外”,指的是绕过React经过addEventListener直接添加的事件处理函数,还有经过setTimeout/setInterval产生的异步调用。html
缘由:在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state仍是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,可是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改成true,而当React在调用事件处理函数以前就会调用这个batchedUpdates,形成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。前端
class App extends React.Component { state = { val: 0 } componentDidMount() { this.setState({ val: this.state.val + 1 }) console.log(this.state.val) // 0 在钩子函数中不会当即更新 this.setState({ val: this.state.val + 1 }) console.log(this.state.val) // 0 在钩子函数中不会当即更新 setTimeout(_ => { this.setState({ val: this.state.val + 1 }) console.log(this.state.val); // 2 这里会当即更新,而且因为setstate批量更新测量,componentDidMount的两次setstate只会取最后一次,即1 this.setState({ val: this.state.val + 1 }) console.log(this.state.val) // 3 同上 }, 0) } render() { return <div>{this.state.val}</div> } }
在 React 中,咱们一般有一个组件树。若是任何一个组件发生错误,它将破坏整个组件树。没有办法捕捉这些错误,咱们能够用错误边界优雅地处理这些错误。node
错误边界有两个做用react
下面是ErrorBoundary
类的一个例子。若是类实现了 getDerivedStateFromError
或componentDidCatch
这两个生命周期方法的任何一下,,那么这个类就会成为ErrorBoundary。前者返回{hasError: true}
来呈现回退UI,后者用于记录错误。jquery
export class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI. return { hasError: true }; } componentDidCatch(error, info) { // You can also log the error to an error reporting service console.log('Error::::', error); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1\>OOPS!. WE ARE LOOKING INTO IT.</h1\>; } return this.props.children; } }
super
并将props
做为参数传入的做用是啥?在调用super()
方法以前,子类构造函数没法使用this
引用,ES6 子类也是如此。将props
参数传递给super()
调用的主要缘由是在子构造函数中可以经过this.props
来获取传入的props
。webpack
传递 propsgit
class MyComponent extends React.Component { constructor(props) { super(props); console.log(this.props); // { name: 'sudheer',age: 30 } } }
没有传递 propsweb
class MyComponent extends React.Component { constructor(props) { super(); console.log(this.props); // undefined // 可是 Props 参数仍然可用 console.log(props); // Prints { name: 'sudheer',age: 30 } } render() { // 构造函数外部不受影响 console.log(this.props) // { name: 'sudheer',age: 30 } } }
查看正则表达式
gulp是基于任务和流的处理。放在之前好比我想用sass写css, coffee写js, 我必须手动的用相应的compiler去编译各自的文件,而后各自minify。这时候designer给你了两张新图片,好嘞,接着用本身的小工具手动去压缩图片。
后来前端人不能忍了,搞出个自动化这个流程的 Grunt/Gulp, 好比你写完代码后要想发布production版本,用一句gulp build
就能够
rm掉 dist文件夹中之前的旧文件 自动把sass编译成css, coffee编译成js 压缩各自的文件,压缩图片,生成图片sprite 拷贝minified/uglified 文件到 dist 文件夹
webpack是基于入口的。webpack会自动地递归解析入口所须要加载的全部资源文件,而后用不一样的Loader来处理不一样的文件,用Plugin来扩展webpack功能。
loader中采起compose的洋葱模型,内部采用reduceRight实现,所以是后写的先执行
function compose(...loaders){ return function(arg){ return loaders.reduceRight((res, cur) => { return cur(res) }, arg) } }
UglifyES
压缩ES6
代码loader
。 因此Loader的做用是让webpack拥有了加载和解析非js文件的能力。module.rules
中配置,也就是说他做为模块的解析规则而存在。 类型为数组,每一项都是一个Object
,里面描述了对于什么类型的文件(test
),使用什么加载(loader
)和使用的参数(options
)plugins
中单独配置。 类型为数组,每一项是一个plugin
的实例,参数都经过构造函数传入。因为loader对于文件的转换很耗时,因此须要让尽可能少的文件被处理,经过修改test,use,include或者exclude配置来实现
module.exports = { module : { rules : [{ //若是项目源码中只有 文件,就不要写成/\jsx?$/,以提高正则表达式的性能 test: /\.js$/, //babel -loader 支持缓存转换出的结果,经过 cacheDirectory 选项开启 use: ['babel-loader?cacheDirectory'] , //只对项目根目录下 src 目录中的文件采用 babel-loader include: path.resolve(__dirname,'src'), }], } }
resolve.modules默认值是['node_modules'],webpack查找模块的机制和nodejs很相似,先从当前目录的node_modules下去找,找不到再去上一级../node_modules,以此类推。前端大部分项目node_modules都是在根目录,所以直接配置以下方式能够减小查找
module.exports = { resolve: { modules: [path.resolve( __dirname,'node modules')] }, }
经过以下配置使得没有模块化的第三方库无需被解析
module.exports = { module: { noParse: /jquery/, } };
因为webpack是单线程处理,因此只能一个个处理任务。happyPack能够将任务拆分红多个分配给子进程并发处理,子进程都处理完了再通知主线程
const HappyPack = require('happypack') const os = require('os') const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }) { test: /\.js$/, // loader: 'babel-loader', loader: 'happypack/loader?id=happy-babel-js', // 增长新的HappyPack构建loader include: [resolve('src')], exclude: /node_modules/, } plugins: [ new HappyPack({ id: 'happy-babel-js', loaders: ['babel-loader?cacheDirectory=true'], threadPool: happyThreadPool }) ]
webpack提供的UglifyJS只能单线程的一个个压缩js文件(压缩JS代码须要先把代码解析成用Object抽象表示的AST语法树,再去应用各类规则分析和处理AST,致使这个过程耗时很是大),而经过使用ParallelUglifyPlugin能够开启多个子进程并行使用UglifyJS压缩每一个任务
Tree Shaking 正常工做的前提是,提交给 Webpack 的 JavaScript 代码必须采用了 ES6 的模块化语法,由于 ES6 模块化语法是静态的,能够进行静态分析。
首先,为了将采用 ES6 模块化的代码提交给 Webpack ,须要配置 Babel 以让其保留 ES6 模块化语句。修改 .babelrc 文件以下:
{ 'presets':[ [ 'env',{ 'module':false } ] ] }
第二个要求,须要使用UglifyJsPlugin插件。若是在mode:"production"模式,这个插件已经默认添加了,若是在其它模式下,能够手工添加它。
另外要记住的是打开optimization.usedExports。在mode: "production"模式下,它也是默认打开了的。它告诉webpack每一个模块明确使用exports。这样以后,webpack会在打包文件中添加诸如/* unused harmony export */这样的注释,其后UglifyJsPlugin插件会对这些注释做出理解。
module.exports = { mode: 'none', optimization: { minimize: true, minimizer: [ new UglifyJsPlugin() ], usedExports: true, sideEffects: true } }
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行如下流程:
在以上过程当中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,而且插件能够调用 Webpack 提供的 API 改变 Webpack 的运行结果。
浏览器从关闭状态进行启动,而后新开 1 个页面至少须要 1 个网络进程、1 个浏览器进程、1 个 GPU 进程以及 1 个渲染进程,共 4 个进程;后续再新开标签页,浏览器、网络进程、GPU进程是共享的,不会从新启动,若是2个页面属于同一站点的话,而且从a页面中打开的b页面,那么他们也会共用一个渲染进程,不然新开一个渲染进程。
最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程。
简言之,客户端先向服务端发送消息,证实了客户端的发送能力,服务端接受消息后向客户端发送,证实了服务端的接收和发送能力,最后客户端接收到消息向服务端告知,证实了客户端的接受能力。
完成了三次握手,客户端和服务器端就能够开始传送数据。
ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0。
TCP协议规定,只有ACK=1时有效,也规定链接创建后全部发送的报文的ACK必须为1。
SYN(SYNchronization) : 在链接创建时用来同步序号。当SYN=1而ACK=0时,代表这是一个链接请求报文。对方若赞成创建链接,则应在响应报文中使SYN=1和ACK=1. 所以, SYN置1就表示这是一个链接请求或链接接受报文。
FIN (finis)即完,终结的意思, 用来释放一个链接。当 FIN = 1 时,代表此报文段的发送方的数据已经发送完毕,并要求释放链接。
https的握手阶段相比http多了一个ssl/tls协议。
该协议有这三个做用:
(1) 全部信息都是加密传播,第三方没法窃听。
(2) 具备校验机制,一旦被篡改,通讯双方会马上发现。
(3) 配备身份证书,防止身份被冒充。
ssl/tls协议的核心思想是采用公钥加密。客户端向服务器索要公钥,利用公钥对传输的信息加密,服务端收到密文后用私钥解密。
但是这个过程会产生两个问题
(1)如何保证公钥不被篡改?
解决方法:将公钥放在[数字证书](http://en.wikipedia.org/wiki/Digital_certificate)中。只要证书是可信的,公钥就是可信的。
(2)公钥加密计算量太大,如何减小耗用的时间?
解决方法:每一次对话(session),客户端和服务器端都生成一个"对话密钥"(session key),用它来加密信息。因为"对话密钥"是对称加密,因此运算速度很是快,而服务器公钥只用于加密"对话密钥"自己,这样就减小了加密运算的消耗时间。
所以ssl/tls协议的基本过程就是这样的
(1) 客户端向服务器端索要并验证公钥。
(2) 双方协商生成"对话密钥"。
(3) 双方采用"对话密钥"进行加密通讯。
而前两步就是握手阶段。这其中涉及四次握手,且都是明文
首先,客户端(一般是浏览器)先向服务器发出加密通讯的请求,这被叫作ClientHello请求。
在这一步,客户端主要向服务器提供如下信息。
(1) 支持的协议版本,好比TLS 1.0版。(2) 一个客户端生成的随机数,稍后用于生成"对话密钥"。
(3) 支持的加密方法,好比RSA公钥加密。
(4) 支持的压缩方法。
这里须要注意的是,客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,不然会分不清应该向客户端提供哪个网站的数字证书。这就是为何一般一台服务器只能有一张数字证书的缘由。
对于虚拟主机的用户来讲,这固然很不方便。2006年,TLS协议加入了一个Server Name Indication扩展,容许客户端向服务器提供它所请求的域名。
服务器收到客户端请求后,向客户端发出回应,这叫作SeverHello。服务器的回应包含如下内容。
(1) 确认使用的加密通讯协议版本,好比TLS 1.0版本。若是浏览器与服务器支持的版本不一致,服务器关闭加密通讯。(2) 一个服务器生成的随机数,稍后用于生成"对话密钥"。
(3) 确认使用的加密方法,好比RSA公钥加密。
(4) 服务器证书。
除了上面这些信息,若是服务器须要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书"。好比,金融机构每每只容许认证客户连入本身的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。
客户端收到服务器回应之后,首先验证服务器证书。若是证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已通过期,就会向访问者显示一个警告,由其选择是否还要继续通讯。
若是证书没有问题,客户端就会从证书中取出服务器的公钥。而后,向服务器发送下面三项信息。
(1) 一个随机数。该随机数用服务器公钥加密,防止被窃听。(2) 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
(3) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的全部内容的hash值,用来供服务器校验。
上面第一项的随机数,是整个握手阶段出现的第三个随机数,又称"pre-master key"。有了它之后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。
至于为何必定要用三个随机数,来生成"会话密钥",dog250解释得很好:
"无论是客户端仍是服务器,都须要随机数,这样生成的密钥才不会每次都同样。因为SSL协议中证书是静态的,所以十分有必要引入一种随机因素来保证协商出来的密钥的随机性。对于RSA密钥交换算法来讲,pre-master-key自己就是一个随机数,再加上hello消息中的随机,三个随机数经过一个密钥导出器最终导出一个对称密钥。
pre master的存在在于SSL协议不信任每一个主机都能产生彻底随机的随机数,若是随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret做为密钥就不合适了,所以必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能彻底不随机,但是是三个伪随机就十分接近随机了,每增长一个自由度,随机性增长的可不是一。"
此外,若是前一步,服务器要求客户端证书,客户端会在这一步发送证书及相关信息。
服务器收到客户端的第三个随机数pre-master key以后,计算生成本次会话所用的"会话密钥"。而后,向客户端最后发送下面信息。
(1)编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的全部内容的hash值,用来供客户端校验。
至此,整个握手阶段所有结束。接下来,客户端与服务器进入加密通讯,就彻底是使用普通的HTTP协议,只不过用"会话密钥"加密内容。
每秒中计算一次网页的 FPS 值,得到一列数据,而后分析。通俗地解释就是,经过 requestAnimationFrame API 来定时执行一些 JS 代码,若是浏览器卡顿,没法很好地保证渲染的频率,1s 中 frame 没法达到 60 帧,便可间接地反映浏览器的渲染帧率。