halo,你們好,我是132,你們很久不賤了哈!html
最近上課真的很忙,時間不多的用來寫代碼了::>_<::,今天主要給你們帶來的是一個新框架 voe前端
然而並非……vue
voe 是一個底層小程序框架node
意思是它實現了小程序的雙線程,利用「沙箱」 隔離 web 環境,屏蔽 dom 能力react
接下來結合 微信小程序 介紹一下主要思路:git
絕對的控制力,意思是用戶不能操做 dom,不能使用 web API,不能使用完整的 jsx 和 html,不能……反正就是啥都不能!github
就好像 sm 角色同樣,s 對 m 的絕對控制與虐待,m 只能服從命令與受虐web
因此我把小程序的雙線程架構又稱爲 【主奴架構】算法
小程序中不能操做 dom,不是由於它屏蔽了 dom API 或者屏蔽了事件,這樣作是不切實際的小程序
你們都是尋找一個非 dom 環境做爲沙箱,好比 v8,好比 worker,好比 native,好比 wasm
以上都是 OK 的,我猜微信小程序等也是用的相似的沙箱
voe 使用 web worker 做爲沙箱
爲何不使用 v8 或 native?
這就是純粹的我的選擇了,不選擇 v8 或 native 應該是,可是恰恰我我的更偏前一點,web worker 的計算力默認是優於 v8 或 native 的(同等硬件水平),可是 v8 也有好處,好比 node 可使用 cookie,而後擁有一些先進的 API
重點來了,兩個線程中,如何安排框架工做呢?
有幾個原則:
因而乎,就變成下面這個樣子:
而後,困難如約而至,沙箱與主線程之間的鴻溝來自 dom 元素和 事件函數,這二者沒法傳遞
我絞盡腦汁,想了一個徹底之策
將不能傳遞的東西保存到本身線程中並創建映射,將索引傳到另外一個線程
好比,事件是這樣傳遞的:
let handlers = new WeakSet()
if (props) {
for (const k in props) {
if (k[0] === 'o' && k[1] === 'n') {
let e = props[k]
let id = handlers.size + 1
handlers.set({ id: e })
props[k] = id
}
}
}
複製代碼
將事件放到 map 中存起來,而後將 id 傳給主線程,主線程事件觸發的時候,將 id 和 event 參數交還給 worker
for (const k in props) {
if (k[0] === 'o' && k[1] === 'n') {
let id = props[k]
props[k] = event => {
// 不能傳太多,此處省略對事件的簡化操做
worker.postMessage({
type: EVENT,
event,
id
})
}
}
}
複製代碼
而後在 worker 中,根據索引映射,找到對應的事件並觸發
是的沒錯就是這樣,這個方法是萬能的,好比咱們的 diff 方法
既然 diff 沒法將 dom 傳出去,那麼咱們就傳 dom 的 index
if (oldVNode ==null||oldVNode.type!==newVNode.type) {
parent.insertBefore(createNode(newVNode), node)
}
複製代碼
好比這個方法,parent 和 node 都是 dom 元素,是沒辦法傳遞的,咱們就……傳他們的索引,may be 長這樣:
[ [0,'insertBefore',1] ]
複製代碼
dom 是這樣的:
<div id="root" index="0">
<ul index="1">
<li index="2" />
<li index="3" />
</ul>
</div>
複製代碼
若是此時咱們要刪除 index 爲 3 的節點,那對應生成的結構,應該是這樣:
[ [1,'removeChild',3] ]
複製代碼
刺不刺激,咱們成功找到了一個思路,可以實現不一樣的 diff 算法啦
要知道,微信小程序就沒有找到相似的思路,他們的 diff 仍是 virtual-dom 的那套古老的深度遍歷,代碼多性能差……
按照一樣的思路,咱們還能夠在在 worker 中將主線程的函數的參數傳到主線程
好比咱們模擬一個 alert 方法,就能夠這麼作:
function alert(text){
postMessage({
name:'alert',
text
})
}
複製代碼
而後主線程接收參數,並執行
worker.onmessage = {data} => window[data.name](data.text)
複製代碼
如此,完美,這樣咱們就能夠在 worker 中選擇性的使用主線程的方法和變量了
綜上所述,上面介紹了雙線程的主要思路,這些思路不只僅適用於這個框架,一樣適用於其餘跨端的場景
這裏簡單說一下 vue 3,嗯你們看到,voe 的名字和 API 神似 vue 3,事實上我確實將 vue 3 的核心抄過來了,包括依賴收集,響應式,狀態更新,組合函數……
這只是順手的事兒,其實比起 voe 的核心思路,API 是沒什麼所謂的
由於幾乎全部的公司,若是想要搞本身的小程序,都只能過來參考思路,而後 API 極可能就和微信保持一致了
因此我以爲 vue 3 的 API 足夠簡單,正好能夠弱化 API
就抄過來了……
你們能夠能夠將 voe 做爲 vue 3 的最小實現,用於協助閱讀源碼也是很 OK 的哈!
題外話,你們應該都知道我以前寫的框架 fre.js,也應該對 concurrent(時間切片)、suspense 等異步渲染的機制有所瞭解
現在我又來搞 web worker,是由於它倆的思路是相似的,場景也是同樣的
二者的場景一樣都是可視化,高幀率動畫,大量數據與計算……
惋惜自己這種場景需求實在太少了,因此 preact 和 vue 團隊紛紛發聲,表示不想搞也不須要搞::>_<::
可是到我這來講的話,其實我不在乎框架有沒有人用,也不在於業務的,我更加傾向於一種技術創新,因此從這個方面,只要是新的思路,總歸有它的價值
呼~終於寫完了,在掘金髮文,必需要長啊
最後放上 voe 的 github:
歡迎關注與 star!
另外創建了一個前端羣,用於交流各類 new idea:813783512