作者|狼叔(阿里前端技能专家,Node技能布道者)
编辑|覃云
你好,我是阿里巴巴前端技能专家狼叔,在上一篇文章中,我分享了大前真个现状和未来,接下来的这篇文章,我将会分享一些大前端跟 Node.js 结合比较密切的点。

Node.js 在大前端布局里意义重大,除了基本构建和 Web 做事外,这里我还想讲两点。
首先它冲破了原有的前端边界,之前运用开拓只分前端和 API 开拓。但通过引入 Node.js 做 BFF 这样的 API proxy 中间层,使得 API 开拓也成了前真个事情范围,让后端同学专注于开拓 RPC 做事,很明显这样明确的分工是极好的。
其次,在前端开拓过程中,有很多问题不依赖做事器端是做不到的,比如场景的性能优化,在利用 React 后,导致 bundle 过大,首屏渲染韶光过长,而且存在 SEO 问题,这时候利用 Node.js 做 SSR 就是非常好的。
当然,前端开拓 Node.js 还是存在一些本钱,要理解运维等,会略微繁芜一些,不过也有办理方案,比如 Servlerless 就可以降级运维本钱,又能完成前端开拓。直白点讲,在已有 Node.js 拓展的边界内,降级运维本钱,提高开拓的灵巧性,这一定会是一个大趋势。
2018 年 Node.js 发展的非常好,InfoQ 曾翻译过一篇文章《2018 Node.js 用户调查报告显示社区仍旧在快速发展》。2018 年 5 月 31 日,Node.js 基金会发布了 2018 年用户调查报告,涵盖了来自 100 多个国家 1600 多名参与者的见地。报告显示,Node.js 的利用量仍旧在快速增长,超过¾的参与者期望在来年扩展他们的利用场景,其余和 2017 年的报告比较,Node 的易学程度有了大幅提升。
该调查远非 Node 快速增长的唯一指征。根据 ModuleCounts.com 的数据,Node 的包注册中央 NPM 每天会增加 507 个包,比较下一名要多 4 倍多。2018 年 Stack Overflow 调查也有类似的结果,JavaScript 是利用最广泛的措辞,Node.js 是利用最广泛的框架。
本节我会紧张分享一些跟 Node.js 结合比较密切的点:首先先容一下 API 演进与 GraphQL,然后讲一下 SSR 如何结合 API 落地,构建出具有 Node.js 特色的做事,然后再简要先容下 Node.js 的新特性、新书等,末了聊聊我对Deno 的一点意见。
API 演进与看起来较火的 GraphQL书本上的软件工程在互联网高速发展的本日已经不那么适用了,尤其是移动开拓火起来之后,所有企业都崇尚敏捷开拓,快鱼吃慢鱼,乃至以为 2 周发一个迭代版本都慢,后面组件化和热更新便是这样产生的。综上各类,我们对传统的软件工程势必要重新思考,如何提高开拓和产品迭代效率成为重中之重。
先反思一下,开拓为什么不那么高效?
从传统软件开拓过程中,可以看到,需求提出后,先要设计出 ui/ue,然后后端写接口,再然后 APP、H5 和前端这 3 端才能开始开拓,以是串行的流程效率极低。
于是就有了 mock api 的观点。通过静态 API 仿照,使得需求和 ue 出来之后,就能确定静态 API,造一些仿照数据,这样 3 端 + 后端就可以同时开拓了。这曾经是提效的非常大略直接的办法。
静态 API 实现有很多种办法,比如大略的基于 Express / Koa 这样的成熟框架,也可以采取专门的静态 API 框架,比如著名的 typicode/json-server,想实现 REST API,你只须要编辑 db.json,放入你的数据即可。
{ \公众posts\"大众: [ { \"大众id\"大众: 1, \公众title\"大众: \"大众json-server\"大众, \"大众author\"大众: \"大众typicode\"大众 } ], \"大众comments\公众: [ { \"大众id\"大众: 1, \"大众body\"大众: \"大众some comment\"大众, \"大众postId\公众: 1 } ], \"大众profile\公众: { \"大众name\"大众: \"大众typicode\公众 }}
启动做事器:
$ json-server --watch db.json
此时访问网址 http://localhost:3000/posts/1,即我们刚才仿造的静态 API 接口,返回数据如下:
{ \"大众id\"大众: 1, \公众title\"大众: \"大众json-server\"大众, \公众author\"大众: \"大众typicode\"大众 }
还有更好的办理方案,比如 YApi ,它是一个可本地支配的、打通前后端及 QA 的、可视化的接口管理平台:http://yapi.demo.qunar.com/
实在,环绕 API 我们可以做非常多的事儿,比如根据 API 天生要求,对做事器进行反向压测,乃至是 check 后端接口是否非常等。很明显,这对前端来说是极其友好的。下面是我几年前画的图,列出了我们能环绕 API 做的事儿,至今也不算过期。
通过社区,我们可以理解到当下主流的 API 演进过程。
1.GitHub v3 的 restful api,经典 rest;
2. 微博 API,非常传统的 json 约定办法;
3. 在 GitHub 的 v4 版本里,利用 GraphQL 来构建 API,这也是个趋势。
GraphQL 目前看起来比较火,那 GitHub 利用 GraphQL 到底办理的是什么问题呢?
GraphQL 既是一种用于 API 的查询措辞也是一个知足你数据查询的运行时。
下面看一个最大略的例子:
首先定义一个模型;然后要求你想要的数据;末了返回结果。很明显,这和静态 API 仿照是一样的流程。但 GraphQL 要更强大一些,它可以将这些模型和定义好的 API 和后端很好的集成。于是 GraphQL 就统一了静态 API 仿照和和后端集成。
开拓者要做的,只是约定模型和 API 查询方法。前后端开拓者都遵守一样的模型开拓约定,这样就可以简化沟通过程,让开发更高效。
如上图所示,GraphQL Server 前面部分,便是静态 API 仿照。GraphQL Server 后面部分便是与各种数据源进行集成,无论是 API、数据还是微做事。是不是很强大?
下面我们总结一下 API 的演进过程。
传统办法:Fe 仿照静态 API,后端参照静态 API 去演习 rpc 做事。
时髦的办法:有了 GraphQL 之后,直接在 GraphQL 上编写模型,通过 GraphQL 供应静态 API,省去了之前开拓者自己仿照 API 的问题。有了 GraphQL 模型和查询,利用 GraphQL 供应的后端集成办法,后端集成更大略,于是 GraphQL 成了前后端解耦的桥梁。
集成利用的便是基于 Apollo 团队的 GraphQL 全栈办理方案,从后端到前端供应了对应的 lib ,使得前后端开拓者利用 GraphQL 更加的方便。
GraphQL 本身是好东西,和 Rest 一样,我的担心是落地不一定那么随意马虎,毕竟接管约定和规范是很麻烦的一件事儿。可是不做,又怎么能进步呢?
构建具有 Node.js 特色的做事2018 年,有一个出乎猜想的一个实践,便是在浏览器可以直接调用 grpc 做事。RPC 做事暴漏 HTTP 接口,这事儿 API 网关就可以做到。事实上,gRPC-Web 也是这样做的。
如果只是大略透传,意义不大。大多数情形,我们还是要在 Node.js 端做做事聚合,继而为不同端供应不一样的 API。这是比较范例的 API Proxy 用法,当然也可以叫 BFF(backend for frontend)。
从前端角度看,渲染和 API 是两大部分,API 部分前端自己做有两点好处:
1. 前端更理解前端需求,尤其是根据 ui/ue 设计 API;
2. 让后端更专注于做事,而非 API。需求变更,能不折腾后端就只管即便不要去折腾后端。这也是应变的最好办法。
构建具有 Node.js 特色的微做事,也紧张从 API 和渲染两部分动手为主。如果说能算得上创新的,那便是 API 和渲染如何无缝结合,让前端开拓有更好的效率和体验。
只管 Node.js 中间层可以将 RPC 做事聚合成 API,但前端还是前端,API 还是 API。那么如何能够让它们连接到一起呢?比较好的办法便是通过 SSR 进行同构开拓。做事端创新有限,搞来搞去便是不断的升 v8,提升性能,新东西不多。
本日我最头疼的是,被 Vue/React/Angular 三大框架绑定,喜忧参半,既想用组件化和双向绑定(或者说不得不用),又希望保留足够的灵巧性。大家都知道 SSR 由于事宜 /timer 和过长的相应韶光而无法有很高的 QPS(够用,优化难),而且对 API 聚合处理也不是很爽。更尴尬的是 SSR 下做前后端分离难熬痛苦,不做也难熬痛苦,到底想让人咋样?
对付任何新技能都是一样的,不上是等去世,上了是找去世。目前是在找去世的路上努力的找一种更舒畅的去世法。
目前,我们紧张采取 React 做 SSR 开拓,上图中的 5 个步骤都经历过了(留到 QCon 广州场分享),这里大略先容一下 React SSR。React 16 现在支持直接渲染到节点流。渲染到流可以减少你内容的第一个字节(TTFB)的韶光,在文档的下一部分天生之前,将文档的开头至结尾发送到浏览器。当内容从做事器流式传输时,浏览器将开始解析 HTML 文档。渲染到流的另一个好处是能够相应背压。
实际上,这意味着如果网络被备份并且不能接管更多的字节,那么渲染器会得到旗子暗记并停息渲染,直到堵塞打消。这意味着你的做事器会利用更少的内存,并更加适应 I / O 条件,这两者都可以帮助你的做事器拥有具有寻衅性的条件。
在 Node.js 里,HTTP 是采取 Stream 实现的,React SSR 可以很好的和 Stream 结合。比如下面这个例子,分 3 步向浏览器进行相应。首先向浏览器写入基本布局 HTML,然后写入 React 组件<MyPage/>,然后写入</div></body></html>。
// 做事器端// using Expressimport { renderToNodeStream } from \"大众react-dom/server\公众import MyPage from \公众./MyPage\"大众app.get(\公众/\"大众, (req, res) => { res.write(\"大众<!DOCTYPE html><html><head><title>My Page</title></head><body>\"大众); res.write(\"大众<div id='content'>\"大众); const stream = renderToNodeStream(<MyPage/>); stream.pipe(res, { end: false }); stream.on('end', () => { res.write(\"大众</div></body></html>\公众); res.end(); });});
这段代码里须要把稳stream.pipe(res, { end: false }),res 本身是 Stream,通过 pipe 和<MyPage/>返回的 stream 进行绑定,继而达到 React 组件嵌入到 HTTP 流的目的。
上面是做事器真个做法,与此同时,你还须要在浏览器端完成组件绑定事情。react-dom 里有 2 个方法,分别是 render 和 hydrate。由于这里采取 renderToNodeStream,和 hydrate 结合利用会更好。当 MyPage 组件的 html 片段写到浏览器里,你须要通过 hydrate 进行绑定,代码如下。
// 浏览器端import { hydrate } from \公众react-dom\"大众import MyPage from \"大众./MyPage\公众hydrate(<MyPage/>, document.getElementById(\"大众content\公众))
可是,如果有多个组件,须要写入多次流呢?利用 renderToString 就大略很多,普通模板的办法,流却使得这种玩法变得很麻烦。
伪代码:
const stream1 = renderToNodeStream(<MyPage/>);const stream2 = renderToNodeStream(<MyTab/>);res.write(stream1)res.write(stream2)res.end()
核心设计是先写入布局,然后写入核心模块,然后再写入其他模块。
1) 布局 (大多数情形静态 html 直接吐出,有可能会有要求);
2) Main(大多数情形有要求);
3) Others。
于是:
class MyComponent extends React.Component { fetch(){ // 获取数据 } parse(){ // 解析,更新 state } render(){ ... }}
在调用组件渲染之前,先得到 renderToNodeStream,然后实行 fetch 和 parse 方法,取到结果之后再将 Stream 写入到浏览器。当前端吸收到这个组件编译后的 html 片段后,就可以根据 containerID 直接写入,当然如果须要,你也可以根据做事器端传过来的 data 进行定制。
前后端如何通信、做事端代码如何打包、css 如何直接插入、和 eggjs 如何集成,这是目前我紧张做的事儿。对付 API 端已经很成熟,对付 SSR 大略的做法也是有的,比如 next.js 通过静态方法 getInitialProps 完成接口要求,但只适用比较大略的运用处景(一键切换 CSR 和 SSR,这点设计的确实是非常奥妙的)。但是如果想更灵巧,处理更卖力的项目,还是很有寻衅的,须要实现上面更为繁芜的模块抽象。在 2019 年,该当会补齐这块,为构建具有 Node.js 特色的做事再拿下一块高地。
Serverless大略地说,Serverless = FAAS + BaaS ,做事如果被认为是 Serverless 的,它必须无需显式地配置,并能自动调度扩缩容以及根据利用情形进行计费。云 function 是当今无 Serverless 打算中的通用元素,并引领着云的简化和通用编程模型发展的方向。
2015 年亚马逊推出了一项名为 AWS Lambda 做事的新选项。Node.js 领域 TJ 大神去创业,开拓了 http://apex.run。目前,各大厂都在 Serverless 上发力,比如 Google、AWS、微软,阿里云等。
这里不得不提一下 Eventloop,Node.js 成也 Eventloop,败也 Eventloop,本身 Eventloop 是黑盒,开拓将什么样的代码放进去你是很难全部覆盖的,偶尔会涌现 Eventloop 壅塞的情形,排查起来极为痛楚。
而利用 Serverless,可以有效的防止 Eventloop 壅塞。比如加密,加密是常见场景,但本身的实行效率非常慢。如果加解密和你的其他任务放到一起,很随意马虎导致 Eventloop 壅塞。
如果加解密做事是独立的做事呢?比如在 AWS 的 Lambda 上发布上面的代码,它自身是独立的,按需来动态扩容机器,可以去除 CPU 密集操为难刁难 Node.js 的影响,快速相应流量变革。
这是趋势,对付活动类的尤其划算。你不知道什么时候是峰值,须要快速动态扩容能力,你也不会一贯利用,按需付费更好。就算这个做事挂了,对其他业务也不会有什么影响,更不会涌现壅塞 Eventloop 导致雪崩的情形。
可靠性:99.999999999%可用性:99.99%无限存储空间按量付费在前端领域,Serverless 会越来越受欢迎,除了能完成 API Proxy,BFF 这种功能外,还可以减少前端运维本钱,还是可以期望一下的。
Node.js 新特性2018 年有一个大家玩坏的梗:想提升性能,最大略的办法便是升级到最新 LTS 版本。由于 Node.js 依赖 v8 引擎,每次 v8 发版优化,新版 Node.js 集成新版 v8,于是性能就被提升了。
其他手段,比如利用 fast-json-stringify 加速 JSON 序列化,通过 Schema 知道每个字段的类型,那么就不须要遍历、识别字段类型,而是可以直接用序列化对应的字段,这就大大减少了打算开销,这便是 fast-json-stringfy 的事理,在某些情形下乃至可以比 JSON.stringify 快靠近 10 倍旁边。
在 2018 年,Node.js 非常稳定的提高着。下面看一下 Node.js 发版情形,2018-04-24 发布 Node.js v10,在 2018-10-23 发布 Node.js v11,稳步增长。下图是 Node.js 的发布操持。
可以看到,Node.js 非常稳定,API 也非常稳定,变革不大,一贯紧跟 V8 升级的脚步,不断的提升性能。在新版本里,能够值得一说的,大概就只有 http2 的支持。
在 HTTP/2 里引入的新特性有:
Multiplexing 多路复用Single Connection 每个源一个连接Server Push 做事器端推送Prioritization 要求优先级Header Compression 头部压缩目前,HTTP/2 已经开始落地,并且越来越稳定,高性能。HTTP/2 在 Node.js v8.4 里加入,在 Node.js v10 变为 Stable 状态,大家可以放心利用。示例代码如下。
const http2 = require('http2');const fs = require('fs');const server = http2.createSecureServer({ key: fs.readFileSync('localhost-privkey.pem'), cert: fs.readFileSync('localhost-cert.pem')});server.on('error', (err) => console.error(err));
其他比如 trace_events,async_hooks 等改进都比较小。Node.js 10 将 npm 从 5.7 更新到 v6,并且在 node 10 里增强了 ESM Modules 支持,但还是不是很方便(官方正在实现新的模块加载器),不过很多有名模块已经逐步支持 ESM 特性了,一样平常在 package.json 里增加如下代码。
{ \"大众jsnext:main\"大众: \"大众index.mjs\"大众,}
其余非常处理,终于可以根据 code 来处理了。
try {// foo} catch (err) {if (err.code === 'ERR_ASSERTION') { . . . }else { . . . }}
末了再提 2 个模块:
node-clinic 性能调试神器
https://clinicjs.org
这是一个 Node.js 性能问题的诊断工具,可以天生 CPU、内存利用、事宜循环(Event loop) 延时和生动的句柄的干系数据折线图。
Lowjs 利用 Node.js 去开拓 IoT
https://www.lowjs.org/
Node-RED 构建 IoT 良久前就有了,这里先容一下 Lowjs。Low.js 是 Node.js 的改造版本,可以对低端操作有更好的支持。它是基于内嵌的对内存哀求更低的 js 引擎 DukTape。Low.js 仅需利用不到 2MB 的硬盘和 1.5MB 的内存。
关于 DenoRy 把 Deno 用 Rust 重写了之后,就再也没有人说 Deno 是下一代 Node.js 了。个中的缘故原由大家大概能够想明白,别有用心的人吹水还是很恐怖的。Deno 基于 ts 利用时环境,底层利用 Rust 编写。性能、安全性上都很好,但舍弃了 npm 生态,须要做的事儿还是非常多的,乃至有人将 Koa 移植过去,也是蛮故意思的事儿。如果 Deno 真的能走另一条路,也是非常好的事儿。
未来已来不知道还有多少人还记得,Google 的 ChromeOS 的理念是“浏览器即操作系统”。现在看来,未来已经不远了。通过各种研究,我们有情由武断 Web 崇奉,未来大前真个前景会更好,此时此刻,只是刚刚开始。
这里我再分享一些参加 Google IO 时理解到的信息:
PWA 证明了浏览器的缓存能力;投屏、画中画、push 等原生运用有的功能也都支持了;Web Components 标准化;编解码新方案 av1,效率有极大的提升。为什么会产生这样的改变?缘故原由在于:
Web 开拓主流化,无论移动端还是 PC 端,都能够复用前端技能,又能跨平台,这是 ROI 最高的办法。Node 和 Chrome 一起孕育出了 Electron/Nw.js 这样的打包加壳工具,打通了前端和 Native API 的通道,让 WebView 真正的跨平台。PWA 对付缓存的增加,以及推送、安装过程等抽象,使得 Web 运用拥有了可以媲美 native client 的能力。这里首先要感谢 Chrome+Android 的考试测验,使得 PWA 拥有和 Android 运用同等的报酬和权限。谷歌同时拥有 Chrome 和 Android,以是才能够在上面做整合,进一步扩大 Web 开拓的边界。通过考试测验,开放,终极形成标准,乃至是业界生态。很明显,作为流量入口,节制底层举动步伐能力是无比主要的。
Chrome 还供应了相应 Web 真个 API,如 web pay、web share、credential management api、media session 等。
Chrome 作为入口是恐怖,再结合 Android,使得 Google 轻松完成技能创新,继而形成标准规范,推动其他厂商,一贯领先是恐怖的。
前真个爆发,说来也便是最近 3、4 年的事情,其最根本的创造力根源在 Node.js 的助力。Node.js 让更多人看到了前真个潜力,从做事器端开拓,到各种脚手架、开拓工具,前端开始沉浸在造轮子的天下里无法自拔。组件化后,比如 SSR、PWA 等赞助前端开拓的快速开拓实践你险些躲不过去,再到 API 中间层、代理层到专业的后端开拓都有非常成熟的履历。
我亲历了从 Node 0.10 到 iojs,从 Node v4 到目前的 Node v11,写了很多文章,参加过很多技能大会,也做过很多次演讲,有机会和业内很多高手互换。当然,我也从 Qunar 到阿里,经历了各种 Node 运用处景,对付 Node 的前景我是非常笃定的。长于利用 Node 有无数好处,想快速出成绩,想性能调优,想优化团队构造,想职员招聘,选择 Node 是不会有错的,诸多利好都让我武断的守护 Node.js,至少 5 年以上。
我想跟很多技能人强调的是,作为前端开拓,你不能只会 Web 开拓技能,你须要节制 Node,你须要理解移动端开拓办法,你须要对后端有更多理解。而拥有更多的 Node.js 和架构知识,能够让你如鱼得水,开启大前端更多的可能性。
如果前面有二辆车,一辆是保时捷一辆是众泰,如果你必须撞一辆,你选哪个?
理性思维是哪个代价最低撞哪个,条件是你能够判断这两辆车的代价,很明显保时捷要比众泰贵很多。讲这个的目的是希望大家能够理解全栈的好处。全栈是一种崇奉,不是拿来吹牛逼的,而是真的可以办理更多问题,同时也能让自己的知识体系不留空缺,享受自我实现的极致快乐。其余,如果你须要理解更多的架构知识,全栈也是个不错的选择。
以我为例,我从打仗全栈观点到现在,经历了以下四个阶段:
第一阶段各种折腾,写各种代码,成了一个伪全栈,还挺愉快的;第二阶段折腾开源,创造了新大陆,各种新玩法,好东西,很喜好分享;第三阶段布道,以为别人能行自己也能行,硬抗了二年,很累;第四阶段带人管理,参加超级项目,心脑体都是煎熬,但对心智的打磨很故意思。不忘初心,坚持每天都能写代码,算是我最舒畅自满的事儿了吧,以前说越大越忙,现在要说越老越忙了,有了孩子,带人,还想做点事儿,能安静的写会代码实在不随意马虎。
说了这么多,回到大前端话题,至少目前看 2019 年都是好事,统统都在趋于稳定和标准化,大家不必要过于焦虑。不过,节制学习能力始终是最主要的,还是那两句话:“广积粮,高筑墙,缓称王”,“少抱怨,多思考,未来更美好”。
做一个武断的 Web 崇奉者,把握趋势,选择比努力更主要!
推举阅读
2019年大前端技能趋势深度解读
作者简介
狼叔(网名 i5ting),现为阿里巴巴前端技能专家,Node.js 技能布道者,Node 全栈公众号运营者。曾就职于去哪儿、新浪、网秦,做过前端、后端、数据剖析,是一名全栈技能的实践者,目前紧张关注技能架构和团队梯队培植方向。即将出版《狼书》3 卷。
末了给自己打一个广告,今年 6 月 20 日北京举办的 GMTC 大会上,我会担当 Node 专场出品人,紧张关注 Serverless,TypeScript 在 Web 开拓框架里干系实践,以及性能,SSR,架构干系的 topic,如果你有想法,想分享的话,欢迎联系我。