WebWorker 中將已處理好的 VDOM 數據提交主線程渲染 DOM
上篇文章講了 WebWorker 的簡單用法,其實網上很多類似的文章,我寫的也比較垃圾。不會的建議可以網上看比較好點的資料。
這裏我會先講下我的大致思路。然後會貼上一堆不實用的垃圾代碼供參考。
WebWorker 中必然是無法訪問 DOM 的,更無法創建 DOM 元素。如果想要實現把 Worker 中的東西渲染出來,只能把相關數據什麽的放到主線程去渲染。這用消息機制是可以實現的。
DOM 既然只能在主線程渲染,那麽事件 Worker 線程自然也是無能為力了。而更關鍵的是 Worker 和主線程通信的時候不能傳遞函數作為參數(toString 這種方式不作數),而事件處理程序都是函數。那麽就只好通過一個標識來代替函數,在 Worker 裏通過這個標識來決定具體執行什麽操作。
Worker 和主線程的分工相對是明確的,完善後的代碼也基本上不怎麽會去寫執行在主線程上代碼的,主要還是去寫執行在 Worker 裏面的代碼。而等下次要討論的是如何把 HTML 編譯成類似在下邊的 worker.js 代碼的 render 函數中直接用 JSON 寫的那部分。
再之後要討論 VDOM 相關的算法,到時候不管寫的多爛,能用就行。
之後的之後就討論一些動畫,事件防抖等的處理方式,要放到很久之後才討論了,還有很多沒想好應該什麽時候討論的事情,一步步來吧,想到哪裏就寫到哪裏,我一個純高技術的,還是亂七八糟都學的人確實寫不出多好的東西來,多練習下也許N年後就好些了吧。
這裏直接不涉及任何 VDOM 相關的東西。所有的東西都是用 JSON 來表示而已。也說過以後的文章才會討論 VDOM,我對 VDOM 也是一知半解。搞出的東西不會有多麽高的保障。自己懂得的還是自己去研究的好,但好在這些算法開源的實現很多。學習後換成好點的就行了。
HTML 裏面沒有什麽東西:
1 <div id="root"></div> 2 <script src="main.js"></script>
在主線程中運行的 main.js 中主要是為了渲染 DOM,綁定事件。這裏的代碼遠遠不足以滿足正常使用,但這裏只是為了講一部分想法,沒必要寫那麽復雜。能夠渲染 DOM,綁定個事件就行了。至於更多的需求以後慢慢再討論。這裏聲明,這些代碼完全不足以在項目中使用,不要拿著亂用,不然裏面很多問題你會很難解決的。
1 var worker = new Worker(‘worker.js‘);2 3 worker.addEventListener(‘message‘, function (event) { 4 console.log(event.data); 5 var message = event.data; 6 7 switch (message.type) { 8 case ‘render‘: 9 render(message.payload); 10 break; 11 } 12 }); 13 14 15 function render(data) { 16 var root = document.getElementById(‘root‘); 17 18 root.innerHTML = ‘‘; 19 20 root.appendChild(createElement(data)); 21 } 22 23 function setAttrs(element, attrs) { 24 if (attrs) { 25 for (var name in attrs) { 26 element.setAttribute(name, attrs[name]); 27 } 28 } 29 } 30 31 function setProps(element, props) { 32 if (props) { 33 for (var name in props) { 34 element[name] = props[name]; 35 } 36 } 37 } 38 39 function setEvents(element, events) { 40 if (events) { 41 for (var name in events) { 42 attachEvent(element, name, events[name]); 43 } 44 } 45 } 46 47 function setChildren(element, children) { 48 if (children && children instanceof Array) { 49 children.forEach(function (item) { 50 element.appendChild(createElement(item)); 51 }); 52 } 53 } 54 55 function createElement(data) { 56 if (!data) { 57 return null; 58 } 59 60 var element = document.createElement(data.type); 61 62 setAttrs(element, data.attrs); 63 setProps(element, data.props); 64 setEvents(element, data.events); 65 setChildren(element, data.children); 66 67 return element; 68 } 69 70 var eventBinders = { 71 onTap: { 72 bind: function (element, name, value) { 73 element.addEventListener(‘click‘, function () { 74 worker.postMessage({ 75 type: ‘command‘, 76 payload: { 77 name: value 78 } 79 }); 80 }); 81 } 82 } 83 }; 84 85 function attachEvent(element, name, value) { 86 eventBinders[name].bind(element, name, value); 87 } 88 89 function createAttribute(element, name, value) { 90 element.setAttribute(name, value); 91 }
在 Worker 線程中中執行的 worker.js 會處理很多事務。基本上邏輯什麽的都在裏面了。
1 var data = { 2 value: 1 3 }; 4 5 function onDecreaseClick() { 6 data.value -= 1; 7 render(data); 8 } 9 10 function onIncreaseClick() { 11 data.value += 1; 12 render(data); 13 } 14 15 function handleCommand(data) { 16 switch (data.name) { 17 case ‘onDecreaseClick‘: 18 onDecreaseClick(data); 19 break; 20 case ‘onIncreaseClick‘: 21 onIncreaseClick(data); 22 break; 23 } 24 } 25 26 function render(data) { 27 self.postMessage({ 28 type: ‘render‘, 29 payload: { 30 type: ‘div‘, 31 attrs: {}, 32 props: {}, 33 children: [ 34 { 35 type: ‘button‘, 36 events: { 37 onTap: ‘onDecreaseClick‘, 38 }, 39 props: { 40 textContent: ‘Decrease‘ 41 } 42 }, 43 { 44 type: ‘span‘, 45 props: { 46 textContent: data.value 47 } 48 }, 49 { 50 type: ‘button‘, 51 events: { 52 onTap: ‘onIncreaseClick‘, 53 }, 54 props: { 55 textContent: ‘Increase‘ 56 } 57 } 58 ] 59 } 60 }); 61 }68 69 self.addEventListener(‘message‘, function (event) { 70 var message = event.data; 71 72 switch (message.type) { 73 case ‘command‘: 74 handleCommand(message.payload); 75 break; 76 } 77 }); 78 80 render(data);
代碼都很簡單粗暴。雖然確實可以跑起來。但是無論是 DOM 渲染 還是 Worker 中的處理都是很簡單的,同時也是不可實際生產使用的。接下來討論過 VDOM 之後會進一步完善。
這次的東西寫是寫完了,但不知道是不是只有我自己能看懂自己寫的啥。就當練手把。有空把整個項目的實現都寫一遍,復習下也行,感覺不僅文筆差,思路好像也不是很好吧。
WebWorker 中將已處理好的 VDOM 數據提交主線程渲染 DOM