React为大型应用而生。Electron和React-native赋予了它构建移动跨平台app和桌面应用的能力,而Taro曾经赋予了它编写生成各种平台小程序和React-native应用的能力。这里我专门说一下太郎。它是中国制造的。文档写的不错,升级速度也比较快。我想有问题会及时解决。他们的维修人员还是很敬业的!Tips:本文部分知识点介绍如有错误或不完整,敬请指出。本文可能内容较多,阅读时间较长,但希望您能认真阅读。如果可以,最好手工实现一些代码。本文所有代码全部手写。本文将从原生浏览器环境逐步深入介绍到跨平台开发。先给点资料手写React优化脚手架项目react-ssr源码手写Node.js原生静态资源服务器跨平台Electrondemo原生浏览器环境:原生浏览器环境其实是最考验前端能力的编程环境-前端工程师,因为一开始我们的前端大多是面向浏览器编程的,现在很多很多做了5-10年的前端都不知道性能面板API怎么用。你如何看待调用函数?我不知道分析需要多长时间。这也是最近采访的情况。我觉得大家说35岁失业是常有的事,但多半是你在胡闹啊兄弟。在原生浏览器环境下使用React框架,制作单页SPA应用比较常见:原生SPA应用分为以下几种:纯CSR渲染(客户端渲染)纯SSR渲染(服务端渲染)混合渲染(预渲染),webpack的插件预渲染,Next.js的常规路由SSR,或者用Node.js做中间件,做一些SSR,加速首屏渲染,或者指定路由SSR。)下面的将详细介绍这些渲染形式精化渲染,以及优缺点:纯CSR渲染客户端请求RestFul接口,接口返回静态资源文件Node.js实现代码客户端接收一个HTML文件,几个CSS文件,多个javaScript文件用户输入url地址栏然后客户端返回静态文件,客户端开始解析文件,js代码动态生成页面。(这就是单页应用的SEO不友好的原因,最初只是一个空div标签的HTML文件。)判断一个页面是否为CSR,可以通过右键查看页面元素在很大程度上。如果只有一个Emptydiv标签,那么大概率可以说是单页、CSR、客户端渲染的网页。如何细化一个纯CSR应用的渲染?单页采用CSR形式,大部分依赖框架,如Vue、React。一旦采用此类技术架构,状态数据集中管理,数据单向流动,数据不可变,路由懒加载,组件按需加载,合适的缓存机制(PWA技术),组件细化拆分,单体数据源刷新组件,这些都是我们可以细化的方向。往往纯CSR单页应用一般不会太复杂,所以PWA和webwork等这里就不介绍了。后面我会在复杂的跨平台应用中涌入这些技术。单一数据源判断组件是否刷新是最重要的细化方向。一旦业务逻辑非常复杂,假设我们使用dva集中状态管理,同时连接那么多状态树模块,可能会导致状态树模块中的任何数据刷新导致这个组件被刷新,但实际上这个component这个时候不需要刷新。这里可以通过根组件带props传入需要的state,源精确刷新,单变量数据源可追溯性高,调试单向数据流不可变数据更方便,不可变.js库用于实现数据不可变,数据共享,持久化存储,通过is比较,生成的每张map都是唯一的,比较codehash的值,性能比递归或直接比较强很多。当PureComponent较浅且难以使用时,对于一般组件,使用PureComponent减少重复渲染。PureComponent,平时我们创建的React组件一般都是继承自Component,而PureComponent相当于一个更纯粹的Component,处理更新前后的数据。浅层比较。组件仅在数据实际更改时才重新渲染。从而可以大大提高组件的性能。PureComponent的部分源码其实是粗浅的对比,只是对一些特殊的值进行了判断。这里要特别注意,为什么要用immutable.js和pureComponent,因为根组件一旦刷新,React会从上到下逐步刷新整个子孙组件,这样性能损失会比重复渲染要大得多,所以我们不仅需要单一数据源控制组件刷新,偶尔也需要比较nextProps和this.props以及this.state和nextState路由懒加载+shouldComponentUpdate中的代码拆分来加速首屏渲染,也可以减轻压力在服务器上,因为很多人可能会访问你的网页,而不会阅读某些路由的内容。使用react-loadable,支持SSR,非常推荐,官方懒人不支持SSR,这个有点遗憾,这里需要配合Wepback4优化配置,代码拆分Tips:这里需要下载支持动态导入的babel预设包@babel/plugin-syntax-dynamic-import,支持动态导入组件。至此路由懒加载组件和代码拆分已经完成。大功告成,支持SSR。非常好。由于纯CSR网页一般都不会很复杂,这里还有一个方面,就是redux、dva等集中式状态管理的状态是无法在状态树上展示的。实践证明,状态树的频繁更新对于用户体验来说非常重要。这是非常有影响力的。这个异步过程比较耗时。远不如通过props等方式支持组件间通信。原则上除了很多组件共享数据外,使用状态树,否则使用其他方式进行通信。SSR,服务端渲染:服务端渲染可以分为:纯服务端渲染,比如jade、tempalte、ejs等模板引擎进行渲染,然后在前端返回对应的html文件这里,Node.js+express框架也用于混合渲染,使用webpack4插件,预渲染指定路由,指定路由为SSR渲染,后台0代码实现混合渲染,使用Node.js。title和meta标签,更好的SEO优化,其中Node.js也可以同时处理数据,减轻前端的计算负担。我觉得掘金沉三元那篇文章写的很好。后来自己一步步实现了。感觉对SSR有了更透彻的理解。另外,我一直天天写Node.js,略懂Next,Nuxt,服务端渲染,感觉差不多。服务端渲染的本质是在服务端运行一次代码,提前请求回来数据,返回运行的html文件。客户端收到文件后,拉取js代码,给代码注水,然后显示,脱水,js接管页面。同构直出代码可以大大减少首屏渲染时间。经过实践,根据不同的内容和配置,可以缩短40%-65%的时间。但是服务端渲染会给服务器带来压力,所以要根据情况使用。下面是最简单的服务端渲染。服务端直接吐出拼接的html结构字符串:客户端只要访问localhost:3000,就可以获取数据页面,访问服务端渲染核心,保证代码在服务端运行一次。redux的storestatetree中的数据一起返回给客户端,客户端进行脱水渲染。如果保证他们的状态数据和路由是一致的,就可以说是成功的。客户端和服务端的代码和数据必须一致,否则SSR会失败。renderfunction:数据注水、脱水,保持client和serverstore的一致性。上面返回的script标签已经注满水,将server端获取的数据交给全局window下的context属性,我们在初始化clientstore的时候脱水。初始渲染使用服务器获取的数据~这里注意,在组件的componentDidMount生命周期中发送ajax等数据时,先判断状态树中是否有数据。如果有数据,那就不要重复发送请求,造成资源浪费。多级路由SSR入口文件的路由部分修改为:以后可能会有CSS服务端渲染用loader和头盔动态meta,seo优化的title标签等,今天时间紧,所以就不继续写SSR了。构建Electron极其复杂的大数据应用程序。需要用到技术,sqlite、PWA、webwork、原生Node.js、react-window、react-lazyload、C++插件等。第一个提到的是sqlite,嵌入式关系型数据库,轻量级无侵入,标准的sql语句,这里不做过多介绍。PWA,一个渐进式web应用,这里使用webpack4插件,方便快速使用。对于一些不需要存入数据库的数据内容,但是又想拉取一次,多次复用,可以使用这个配置serverce工作也有一套生命周期通常,如果我们要使用ServiceWorker,我们基本上按照以下步骤进行:首先,我们需要在页面的JavaScript主线程中使用serviceWorkerContainer.register()来注册ServiceWorker。在注册过程中,浏览器会在后台启动尝试安装ServiceWorker。如果注册成功,ServiceWorker运行在ServiceWorkerGlobalScope环境中;这是一个特殊的workercontext,它独立于主脚本的运行线程,不具备访问DOM的能力。安装过程在后台启动,安装过程中通常需要缓存一些静态资源。如果成功缓存所有资源,则安装成功。如果任何静态资源缓存失败,则安装失败。这里失败了也没关系,安装会一直继续下去,直到安装成功。如果安装不成功,则无法进行下一步——激活ServiceWorker。要开始激活ServiceWorker,激活步骤必须在ServiceWorker安装成功后开始。当ServiceWorker安装完成后,它会收到一个激活事件(activateevent)。在激活事件的处理函数中,主要操作是清理旧版本ServiceWorker脚本中使用的资源。激活成功后,ServiceWorker可以控制页面,但仅限于ServiceWorker注册成功后打开的页面。也就是说,页面打开时是否有serviceworker决定了serviceworker在下一个页面的生命周期中是否不受控。所以,只有在页面刷新的时候,之前不受ServiceWorker控制的页面才有可能被控制。直接上传代码,存储所有js文件和图片//实际存储根据自己的需要,不是越多越好。PWA不限于这些功能。它具有非常强大的功能。有兴趣的可以去lavas看看。对于经常光顾的老客户,PWA技术可以大幅提升首屏渲染效果。特别是在移动端,可以添加到桌面保存。666~,在PC端,更多的是缓存和处理文件~使用react-lazyload来懒加载你窗口中最初不可见的组件或者懒加载组件进行大数据React渲染,让应用有60FPS-一个很核心的点优化List的长列表。React-virtualized-auto-sizer与windowScroll配合使用,实现复杂页面效果+大数据渲染保持60FPS。上面官网介绍了这些组件~高计算量的工作交给webwrokthread。在这段代码中,变量first和second代表两个输入元素;当其中任何一个的值发生变化时,myWorker.postMessage([first.value,second.value])都会将这两个值组成一个数组发送给worker。您可以在消息中发送任意数量的内容。在worker中收到消息后,我们可以编写这样一个事件处理代码作为响应(worker.js):onmessage处理函数允许我们在收到消息后随时执行一些代码,而消息本身在代码作为一个事件的数据属性被使用。这里我们简单地将这两个数字相乘,然后再次使用postMessage()方法将结果发送回主线程。回到主线程,我们再次使用onmessage来响应worker返回的消息:这里我们获取消息事件的数据,并将其设置为结果的textContent,这样用户就可以直接看到操作的结果.注意:在主线程中使用时,onmessage和postMessage()必须挂在worker对象上,在worker中使用则不挂。原因是,在worker内部,worker实际上是全局范围。注意:当一个消息在主线程和workers之间传递时,它是复制或传递的,而不是共享的。开启web工作线程实际上会消耗主线程一定的性能,但将大量的计算工作交给它也未尝不可。事实上,Node.js和javaScript并不适合做大量的计算工作。这是有目共睹的,尤其是js引擎与GUI渲染线程是存在互斥的。充分利用React的Feber架构diff算法优化项目requestAnimationFrame调用高优先级任务中断调度阶段的遍历。由于新版React的调度阶段是三指针可中断链表遍历,所以这不会影响后面的遍历,也不影响用户交互等行为。使用requestAnimationFrame也可以让浏览器保持一个60帧的动画。使用requestAnimationFrame,当页面处于inactive状态时,页面的屏幕刷新任务会被系统挂起。由于requestAnimationFrame一直与屏幕刷新同步执行,因此它也将被挂起。当页面被激活时,动画会从它停止的地方继续播放,从而节省CPU开销。在一个刷新间隔内多次执行该函数是没有意义的,因为显示每16.7ms刷新一次,多次绘制不会反映到屏幕上。在高频事件(resize、scroll等)中,使用requestAnimationFrame可以避免在刷新区间内出现多次函数执行,既保证了流畅性,又节省了函数执行的开销。有些情况下可以直接使用requestAnimationFrame代替Throttle函数,这样就限制了回调函数的执行频率。requestIdleCallback,这个API目前还不兼容Great,但是在Electron开发中可以使用。两者还是有区别的,这两个API可以解决很多复杂情况下的问题~。当然你也可以用上面的api来封装这个api,不是很复杂。在关注用户体验的时候,如果不希望用户因为一些不重要的任务(比如统计报表)而感到卡顿,那么应该考虑使用requestIdleCallback。因为requestIdleCallback回调执行的前提是当前浏览器处于空闲状态。图中一帧包括用户交互、js执行、requestAnimationFrame调用、布局计算、页面重绘。如果某一帧要执行的任务不多,而上述任务在16ms(1000/60)以内完成,那么这一帧就会有一定的空闲时间,这个时间刚好可以用于执行requestIdleCallback的回调,如下图:使用preload、prefetch、dns-prefetch等指定提前请求指定文件,或者浏览器根据情况决定是否预解析dns提前或按需请求某些资源。这个也可以用webpack4插件来实现。目前京东采用的是这种方案~延迟加载指定的js文件~添加script标签,添加async标签,遇到这个标签先请求,但不要阻塞解析html等文件~,请求返回后立即加载脚本tag,加上defer标签,延迟加载,但是必须在所有脚本加载完毕后才加载,但是这个tag有bug,不知道能不能按时加载。一般只写一篇,React-native和一些细节,写这篇文章太费时间了,后面加原创也不容易,感觉有收获,请大家帮忙关注公众号,点击阅读,谢谢
