近兩年來,Serverless 無疑是前端圈裏最火熱的話題之一,在各類技術峯會、各類技術文章裏都能看到它的身影。若是你是一名前端開發者,必定很奇怪:html
「咱們這些前端切圖仔,爲何要關注 Serverless 這種雲計算的概念?」前端
咱們就從這個話題開始聊起吧。node
這個問題用一句話回答就是:react
「Serverless 解放了端開發者(不只僅是 Web 開發者)的生產力,讓端開發者能夠更快、更好、更靈活地開發各類端上應用,不須要投入太多精力關注於後端服務的實現。」git
下面咱們就來慢慢解釋這句話。github
在前端的史前時代,那個時候甚至尚未」前端工程師「這個職位分類,全部人都是後臺開發,全部的網頁和 Web 應用都是來自於後臺渲染,CGI、PHP (甚至你可能都沒據說過的 Perl)即是當時 Web 技術的代名詞,那個時候的 JS 和 CSS,不過是「切圖仔」在網頁裏寫動效和彈窗的小玩具而已。web
後來,AJAX 技術出現了,最先在 Outlook Web Access 中出現,隨後隨着 Google Map、Gmail 等大型 Web 應用的實踐,逐步爲人所知。這項技術讓頁面內的 JS 也能異步地向服務器發起各類請求,而且把數據渲染到頁面上。這個時候,前端工程師們開始接管視圖層邏輯:數據庫
再後來,Node.js 誕生,大大下降了前端開發者開發一個後臺服務的難度,這也讓前端開發者逐漸接管了接管了渲染邏輯,在這期間,各大前端框架(表明性的 React、Vue)的服務器端渲染也逐步成熟。npm
既然能用 Node.js 來作服務端渲染,那麼拿 Node.js 來寫後臺業務邏輯、實現各類 HTTP API 固然也不在話下,因此在一些公司裏,前端接管業務邏輯,後臺只負責各類底層微服務的架構就出現了,這也是目前不少大公司在實行的架構:小程序
細心的你可能已經注意到了,在這個時候,渲染、HTTP API、後臺業務邏輯這些東西,從端的角度看是屬於服務端的,可是從分工角度看卻屬於前端開發的範疇,這就是 BFF(Backend for Frontend)的概念,它的優點在於:
這就是爲何大公司的不少業務,都開始愈來愈多地招 Node.js 全棧工程師的緣由。
可是 BFF 並非銀彈,它仍是有必定問題的,好比在國內通曉先後端開發的全棧工程師太少,很難撐起大致量的業務開發。並且國內大多數前端工程師缺乏服務端開發的經驗,讓他們運維上百臺服務器和一整套海量服務,有點強人所難:
而 Serverless 正是幫助前端工程師解決運維開發 BFF 的良藥。
Serverless 這個單詞,直譯成中文的話,應該是「無服務器」。固然,這裏的「無服務器」絕對不是說不須要任何服務器資源了,而是說不須要關心服務器的具體運維和管理,只須要寫代碼而後發佈便可。
它包含了 FaaS(函數即服務)和 BaaS(後端即服務)兩大塊功能,把各類基礎設施進行了抽象,即便不熟悉後端的開發者,也能快速高質量地開發出海量、穩定的後端服務,而這對於前端工程師維護 BFF 服務來講,幾乎是量身定作的。
舉一個最簡單的例子,你如今須要上線一個新的 HTTP API(好比 /getUser?id=123
),若是使用 Serverless 服務的話,有多快呢?
你只須要寫下面這個雲函數:
module.exports = async function(events, context) { const { id } = events.query.id const userInfo = await fetchUserInfo(id) // 調用後端微服務,拉取用戶信息 return userInfo }
而後發佈這個雲函數(假設命名爲 getUser
),而且爲它設置一條路由:
cloudbase service:create -f getUser -p /getUser
而後你就能夠經過 https://xxx.com/getUser
來拉取數據了,同時還附贈海量彈性伸縮、異地多活、日誌監控等多方位的能力。
若是你以爲這樣很酷炫,那麼不如來試一試 雲開發 Cloudbase 吧!
雲開發(Cloudbase)是騰訊雲 TCB 團隊(Tencent Cloudbase)出品的雲端一體化產品方案,爲廣大的小程序、Web、移動端開發者提供一站式的 Serverless 服務。
固然這是官方的說法,用人話講就是:
用了雲開發,各個端的開發者就能夠一站式地解決後端服務問題了!
實際上早在 2018 年,雲開發就聯合微信團隊推出了「小程序·雲開發」,若是你對它還不怎麼了解,能夠看這兩篇文章:
而如今,雲開發 For Web 也正式上線了!
雲開發提供了雲數據庫、雲函數、雲存儲、用戶登陸體系等一系列的後端能力,而且提供了各端的 SDK,讓各個端的開發者可以基於這些能力,快速、優質地開發出功能豐富的應用。
Talk is cheap, Show me the code!
口說無憑,咱們仍是來直接看代碼吧!
雲開發提供了一個文檔型的 NoSQL 數據庫,與傳統的雲上數據庫不一樣的是,雲開發的數據庫能夠在各類客戶端內使用 SDK 直接進行讀寫,好比 Web 應用、小程序內、Flutter 客戶端等等。
下面咱們以 Web 應用爲例,展現雲數據庫的一系列功能。
CURD是數據庫最基礎的功能,雲開發 SDK 提供了一套鏈式調用接口,對數據庫進行讀寫:
// 使用 Web 端 SDK const cloudbase = require('tcb-js-sdk') const app = cloudbase.init({ /* 初始化... */ }) const db = app.database() // 插入文檔 await db.collection('messages').add({ author: 'stark', message: 'Hello World!' }) // 查詢文檔 const data = await db.collection('messages').where({ author: 'stark' }).get() // 更新文檔 await db.collection('messages').where({ author: 'stark' }).update({ message: 'Hi, Cloudbase!' }) // 刪除文檔 await db.collection('messages').where({ author: 'stark' }).remove()
普通的查詢可能沒法知足一些複雜的需求,好比聯表、group等等。
雲開發針對這些複雜的查詢場景,推出了聚合搜索的功能,把一系列操做抽象爲一個管道(pipeline),單次執行便可,避免了屢次讀的性能問題,咱們以 group 操做爲例:
const $ = db.command.aggregate const result = await db .collection('message') .aggregate() .group({ // 以 author 字段做爲 key,統計相同 author 的數量 _id: '$author' messagesCount: $.sum(1) }) .end() //=> { "_id": "stark", messagesCount: 12 }
更多的聚合搜索功能,能夠參考:Aggregate | 雲開發 Cloudbase
在訂票、預定、轉帳等等場景下,開發者可能會要求數據庫可以保證一連串讀寫的原子性,避免出現競爭條件,這就是數據庫事務的使用場景。
雲開發數據庫固然也提供了事務功能:
// 啓動事務 const transaction = await db.startTransaction() // 在事務內讀 const data = await transaction.collection('messages') .where({ /* <query> */}) .get() // 在事務內寫 await transaction.collection('messages') .where({ /* <query> */}) .update({ /* <data> */}) // 提交事務 await transaction.commit()
在實時聊天室、實時數據看板等等場景下,咱們常常會須要訂閱數據庫的更新,從而實現實時數據推送。
雲開發的數據庫提供的 watch()
方法就是爲此設計的,每當數據庫符合條件的文檔發生變化時,都會觸發 onChange
回調,示例代碼以下:
await db.collection('messages') .where({/* <query> */}) .watch({ onChange: snapshot => { console.log("收到snapshot!", snapshot) }, onError: error => { console.log("收到error!", error) } })
更多信息能夠參考:數據庫實時推送 | 雲開發 Cloudbase
所謂的雲函數,即是在雲端運行的、事件驅動的一段代碼,它能夠被 SDK 調用,也能夠直接經過 HTTP 調用,還能夠設置定時器讓它按期運行:
// sum.js module.exports = async function(events) { return events.a + events.b }
這一小段代碼很簡單,可是隱藏在它之下的倒是一整套龐大的 FaaS(函數即服務)基礎設施,提供了諸如彈性伸縮、日誌、監控告警等多方面的能力。
使用雲開發的客戶端 SDK,能夠垂手可得地在各個端上調用雲函數,咱們以 Web 應用爲例:
const cloudbase = require("tcb-js-sdk"); const app = cloudbase.init({/* 初始化 */}); app.callFunction({ // 雲函數名稱 name: "sum", // 傳給雲函數的參數 data: { a: 1, b: 2 } }) .then(res => { console.log(res); // 輸出 "3" }) .catch(error);
你也許會以爲 SDK 體積龐大,太沉重了,那麼你也能夠選擇使用 HTTP 來調用雲函數,響應 HTTP 請求。
// hello.js module.exports = function() { return 'Hello, World!' }
而後咱們直接經過命令行發佈這個函數,併爲它建立一條路由:
$ cloudbase functions:deploy hello $ cloudbase service:create -f hello -p /hello
隨後即可以經過 url 直接訪問這個雲函數:
$ curl https://xxx.service.tcloudbase.com/hello Hello, World!
具體能夠參考:https://docs.cloudbase.net/se...
在 Cloudbase 的雲函數內,你能夠直接使用 Node.js SDK,無需在初始化的時候額外注入祕鑰:
const cloudbase = require('@cloudbase/node-sdk') // 無需使用服務端祕鑰 const app = cloudbase.init() const data = await app.database().where().get()
更詳細的內容能夠參考:https://docs.cloudbase.net/ap...
咱們在開發應用的過程當中,常常會遇到圖片、文件上傳的需求,而且可能須要爲這些文件設置 CDN 訪問。傳統的流程是下面這樣的:
但若是使用雲開發,只須要在客戶端調用 uploadFile
,就能夠一步完成上面的三件事情:
const tcb = require("tcb-js-sdk"); const app = tcb.init({ env: 'your-env-id' }) const { fileID } = await app.uploadFile({ // 雲端路徑 cloudPath: "/a/b/c/filename", // 須要上傳的文件,File 類型 filePath: document.getElementById('file').files[0] })
uploadFile
會返回一個 fileID
,是雲開發內文件的惟一標識符,咱們可使用 getTempFileURL
來獲取文件 URL 訪問連接:
const tcb = require("tcb-js-sdk"); const app = tcb.init({ env: 'your-env-id' }) const { fileList } = app.getTempFileURL({ fileList: [ 'cloud://a/b/c' ] }) // fileList 是一個有以下結構的對象數組 // [{ // fileID: 'cloud://a/b/c', // 文件 ID // tempFileURL: 'http://xxx/xxx/xxx', // 臨時文件網絡連接 // maxAge: 120 * 60 * 1000, // 有效期 // }]
更詳細的內容,能夠參考:https://docs.cloudbase.net/st...
雲開發除了上述的基礎功能以外,還提供了一系列的擴展能力,包括但不只限於:
更詳細的內容,能夠參考:https://docs.cloudbase.net/ex...
上面的能力是否是有些讓你看花眼了,徹底不知道要怎麼搭配起來使用?
其實一張圖就能夠解決:
圖中的客戶端SDK包括:
服務端 SDK 包括:
光看示例代碼固然沒有什麼意思,咱們接下來就拿雲開發的一些能力,來快速開發一個實時在線聊天室吧。
項目代碼:https://github.com/TencentClo...
這是一個由 create-react-app
快速生成的腳手架項目,因此大部分構建和工程化的細節這裏就略過不談了,咱們直接來看代碼實現,大體上實現了三個功能,括號中是使用的雲開發能力:
首先是咱們的初始化流程,先使用匿名登陸,而後創建實時數據推送的鏈接:
async function init() { // 使用匿名登陸 await auth.anonymousAuthProvider().signIn(); // 使用 refreshToken 的前 6 位做爲 uid setUid(auth.hasLoginState().credential.refreshToken.slice(0, 6)); // 創建實時數據推送鏈接 await db .collection("messages") .where({}) .watch({ onChange(snapshot) { setList(snapshot.docs); setLoading(false); }, onError(err) { console.log(err); }, }); }
創建實時鏈接以後,集合中的任何變化,都會觸發 onChange()
回調,而後咱們使用 setList()
來更新界面上的消息數據。
固然只讀消息是不夠的,咱們還須要發送消息,具體實現很是簡單,能夠看 sendMessage()
方法,直接使用 add()
方法向數據庫寫入數據就能夠了:
// 發送消息 async function sendMessage() { const message = { timestamp: new Date().getTime(), text, uid, }; await db.collection("test").add(message); // 清空輸入欄 setText(""); }
固然以上只是局部的代碼片斷,總體代碼能夠參考:
https://github.com/TencentClo...
開發完畢以後,咱們即可以使用 雲開發靜態網站 來託管咱們的這個聊天室 Web 應用。
首先咱們構建咱們的應用:
$ npm run build
構建產物會生成到 build
目錄下。
而後咱們發佈到靜態託管便可(託管前,請先開通靜態網站):
$ cloudbase hosting:deploy ./build -e your-env-id
發佈完成後,你即可以經過 https://xxxx.tcb.qcloud.la/xxxx
的來訪問你的應用了。進一步,你還能夠爲它綁定自定義域名。
PS:實際上,雲開發的主頁和官方文檔,就是這樣託管的(畢竟作雲服務的,最重要的就是 Eating your own dog food 嘛)。
固然,除了這個實戰 Demo 之外,還能夠看看一些真正業務的實踐:
給 Web 開發者帶來效率和質量上的提高,幫助他們開發更多更優質的應用,免去運維、後臺開發的煩惱,是雲開發不變的願景。雖然咱們目前已經有了不少強大又方便使用的能力,但這遠不是咱們的終點(實際上咱們纔剛剛起步),在將來咱們將會持續完善下面的能力,進一步完善雲開發的體系:
PS:若是你以爲這篇文章對你有幫助,不妨花幾分鐘時間,來試一試快速開始吧。