您當前的位置:首頁 >> 新車
2019年Node趨勢解讀:大前端如何與Node結合?
發布時間:2019-06-28
 
2019年Node趨勢解讀:大前端如何與Node結合?

作者|狼叔(阿里前端技術專家,Node技術布道者)

編輯|覃云

你好,我是阿里巴巴前端技術專家狼叔,在上一篇文章中,我分享了大前端的現狀和未來,接下來的這篇文章,我將會分享一些大前端跟 Node.js 結合比較密切的點。

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 端才能開始開發,所以串行的流程效率極低。

2019年Node趨勢解讀:大前端如何與Node結合?


于是就有了 mock api 的概念。通過靜態 API 模擬,使得需求和 ue 出來之后,就能確定靜態 API,造一些模擬數據,這樣 3 端 + 后端就可以同時開發了。這曾經是提效的非常簡單直接的方式。

2019年Node趨勢解讀:大前端如何與Node結合?


靜態 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 做的事兒,至今也不算過時。

2019年Node趨勢解讀:大前端如何與Node結合?


通過社區,我們可以了解到當下主流的 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 模擬和和后端集成。

2019年Node趨勢解讀:大前端如何與Node結合?


開發者要做的,只是約定模型和 API 查詢方法。前后端開發者都遵守一樣的模型開發約定,這樣就可以簡化溝通過程,讓開發更高效。

2019年Node趨勢解讀:大前端如何與Node結合?


如上圖所示,GraphQL Server 前面部分,就是靜態 API 模擬。GraphQL Server 后面部分就是與各種數據源進行集成,無論是 API、數據還是微服務。是不是很強大?

下面我們總結一下 API 的演進過程。

傳統方式:Fe 模擬靜態 API,后端參照靜態 API 去實習 rpc 服務。

時髦的方式:有了 GraphQL 之后,直接在 GraphQL 上編寫模型,通過 GraphQL 提供靜態 API,省去了之前開發者自己模擬 API 的問題。有了 GraphQL 模型和查詢,使用 GraphQL 提供的后端集成方式,后端集成更簡單,于是 GraphQL 成了前后端解耦的橋梁。

集成使用的就是基于 Apollo 團隊的 GraphQL 全棧解決方案,從后端到前端提供了對應的 lib ,使得前后端開發者使用 GraphQL 更加的方便。

2019年Node趨勢解讀:大前端如何與Node結合?


GraphQL 本身是好東西,和 Rest 一樣,我的擔心是落地不一定那么容易,畢竟接受約定和規范是很麻煩的一件事兒。可是不做,又怎么能進步呢?

構建具有 Node.js 特色的服務


2019年Node趨勢解讀:大前端如何與Node結合?


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 和渲染如何無縫結合,讓前端開發有更好的效率和體驗。

2019年Node趨勢解讀:大前端如何與Node結合?


盡管 Node.js 中間層可以將 RPC 服務聚合成 API,但前端還是前端,API 還是 API。那么如何能夠讓它們連接到一起呢?比較好的方式就是通過 SSR 進行同構開發。服務端創新有限,搞來搞去就是不斷的升 v8,提升性能,新東西不多。

今天我最頭疼的是,被 Vue/React/Angular 三大框架綁定,喜憂參半,既想用組件化和雙向綁定(或者說不得不用),又希望保留足夠的靈活性。大家都知道 SSR 因為事件 /timer 和過長的響應時間而無法有很高的 QPS(夠用,優化難),而且對 API 聚合處理也不是很爽。更尷尬的是 SSR 下做前后端分離難受,不做也難受,到底想讓人咋樣?

對于任何新技術都是一樣的,不上是等死,上了是找死。目前是在找死的路上努力的找一種更舒服的死法。

2019年Node趨勢解讀:大前端如何與Node結合?


目前,我們主要采用 React 做 SSR 開發,上圖中的 5 個步驟都經歷過了(留到 QCon 廣州場分享),這里簡單介紹一下 React SSR。React 16 現在支持直接渲染到節點流。渲染到流可以減少你內容的第一個字節(TTFB)的時間,在文檔的下一部分生成之前,將文檔的開頭至結尾發送到瀏覽器。當內容從服務器流式傳輸時,瀏覽器將開始解析 HTML 文檔。渲染到流的另一個好處是能夠響應背壓。

實際上,這意味著如果網絡被備份并且不能接受更多的字節,那么渲染器會獲得信號并暫停渲染,直到堵塞清除。這意味著你的服務器會使用更少的內存,并更加適應 I / O 條件,這兩者都可以幫助你的服務器擁有具有挑戰性的條件。

在 Node.js 里,HTTP 是采用 Stream 實現的,React SSR 可以很好的和 Stream 結合。比如下面這個例子,分 3 步向瀏覽器進行響應。首先向瀏覽器寫入基本布局 HTML,然后寫入 React 組件,然后寫入

// 服務器端
// using Express
import { renderToNodeStream } from "react-dom/server"
import MyPage from "./MyPage"
app.get("/", (req, res) => {
res.write("");
res.write("
");
const stream = renderToNodeStream();
stream.pipe(res, { end: false });
stream.on('end', () => {
res.write("
");
res.end();
});
});

這段代碼里需要注意stream.pipe(res, { end: false }),res 本身是 Stream,通過 pipe 和返回的 stream 進行綁定,繼而達到 React 組件嵌入到 HTTP 流的目的。

上面是服務器端的做法,與此同時,你還需要在瀏覽器端完成組件綁定工作。react-dom 里有 2 個方法,分別是 render 和 hydrate。由于這里采用 renderToNodeStream,和 hydrate 結合使用會更好。當 MyPage 組件的 html 片段寫到瀏覽器里,你需要通過 hydrate 進行綁定,代碼如下。

// 瀏覽器端
import { hydrate } from "react-dom"
import MyPage from "./MyPage"
hydrate(, document.getElementById("content"))

可是,如果有多個組件,需要寫入多次流呢?使用 renderToString 就簡單很多,普通模板的方式,流卻使得這種玩法變得很麻煩。

偽代碼:

const stream1 = renderToNodeStream();
const stream2 = renderToNodeStream();
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、微軟,阿里云等。

2019年Node趨勢解讀:大前端如何與Node結合?


這里不得不提一下 Eventloop,Node.js 成也 Eventloop,敗也 Eventloop,本身 Eventloop 是黑盒,開發將什么樣的代碼放進去你是很難全部覆蓋的,偶爾會出現 Eventloop 阻塞的情況,排查起來極為痛苦。

而利用 Serverless,可以有效的防止 Eventloop 阻塞。比如加密,加密是常見場景,但本身的執行效率非常慢。如果加解密和你的其他任務放到一起,很容易導致 Eventloop 阻塞。

2019年Node趨勢解讀:大前端如何與Node結合?


如果加解密服務是獨立的服務呢?比如在 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 的發布計劃。

2019年Node趨勢解讀:大前端如何與Node結合?


可以看到,Node.js 非常穩定,API 也非常穩定,變化不大,一直緊跟 V8 升級的腳步,不斷的提升性能。在新版本里,能夠值得一說的,大概就只有 http2 的支持。

在 HTTP/2 里引入的新特性有:

  • Multiplexing 多路復用
  • Single Connection 每個源一個連接
  • Server Push 服務器端推送
  • Prioritization 請求優先級
  • Header Compression 頭部壓縮


2019年Node趨勢解讀:大前端如何與Node結合?


目前,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) 延時和活躍的句柄的相關數據折線圖。

2019年Node趨勢解讀:大前端如何與Node結合?


Lowjs 使用 Node.js 去開發 IoT

https://www.lowjs.org/

Node-RED 構建 IoT 很久前就有了,這里介紹一下 Lowjs。Low.js 是 Node.js 的改造版本,可以對低端操作有更好的支持。它是基于內嵌的對內存要求更低的 js 引擎 DukTape。Low.js 僅需使用不到 2MB 的硬盤和 1.5MB 的內存。

關于 Deno

Ry 把 Deno 用 Rust 重寫了之后,就再也沒有人說 Deno 是下一代 Node.js 了。其中的原因大家大概能夠想明白,別有用心的人吹水還是很可怕的。Deno 基于 ts 運用時環境,底層使用 Rust 編寫。性能、安全性上都很好,但舍棄了 npm 生態,需要做的事兒還是非常多的,甚至有人將 Koa 移植過去,也是蠻有意思的事兒。如果 Deno 真的能走另一條路,也是非常好的事兒。

未來已來

不知道還有多少人還記得,Google 的 ChromeOS 的理念是“瀏覽器即操作系統”。現在看來,未來已經不遠了。通過各種研究,我們有理由堅定 Web 信仰,未來大前端的前景會更好,此時此刻,只是剛剛開始。

2019年Node趨勢解讀:大前端如何與Node結合?


這里我再分享一些參加 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 輕松完成技術創新,繼而形成標準規范,推動其他廠商,一直領先是可怕的。

2019年Node趨勢解讀:大前端如何與Node結合?


前端的爆發,說來也就是最近 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年Node趨勢解讀:大前端如何與Node結合?


理性思維是哪個代價最低撞哪個,前提是你能夠判斷這兩輛車的價值,很明顯保時捷要比眾泰貴很多。講這個的目的是希望大家能夠理解全棧的好處。全棧是一種信仰,不是拿來吹牛逼的,而是真的可以解決更多問題,同時也能讓自己的知識體系不留空白,享受自我實現的極致快樂。另外,如果你需要了解更多的架構知識,全棧也是個不錯的選擇。

以我為例,我從接觸全棧概念到現在,經歷了以下四個階段:

  • 第一階段各種折騰,寫各種代碼,成了一個偽全棧,還挺開心的;
  • 第二階段折騰開源,發現了新大陸,各種新玩法,好東西,很喜歡分享;
  • 第三階段布道,覺得別人能行自己也能行,硬抗了二年,很累;
  • 第四階段帶人管理,參加超級項目,心腦體都是煎熬,但對心智的打磨很有意思。

不忘初心,堅持每天都能寫代碼,算是我最舒服自豪的事兒了吧,以前說越大越忙,現在要說越老越忙了,有了孩子,帶人,還想做點事兒,能安靜的寫會代碼其實不容易。

說了這么多,回到大前端話題,至少目前看 2019 年都是好事,一切都在趨于穩定和標準化,大家不必要過于焦慮。不過,掌握學習能力始終是最重要的,還是那兩句話:“廣積糧,高筑墻,緩稱王”,“少抱怨,多思考,未來更美好”。

做一個堅定的 Web 信仰者,把握趨勢,選擇比努力更重要!

推薦閱讀

2019年大前端技術趨勢深度解讀

作者簡介

狼叔(網名 i5ting),現為阿里巴巴前端技術專家,Node.js 技術布道者,Node 全棧公眾號運營者。曾就職于去哪兒、新浪、網秦,做過前端、后端、數據分析,是一名全棧技術的實踐者,目前主要關注技術架構和團隊梯隊建設方向。即將出版《狼書》3 卷。

最后給自己打一個廣告,今年 6 月 20 日北京舉辦的 GMTC 大會上,我會擔任 Node 專場出品人,主要關注 Serverless,TypeScript 在 Web 開發框架里相關實踐,以及性能,SSR,架構相關的 topic,如果你有想法,想分享的話,歡迎聯系我。

内蒙古十一选五开奖图