1. 程式人生 > >WebWorker 中將已處理好的 VDOM 資料提交主執行緒渲染 DOM

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 之後會進一步完善。

這次的東西寫是寫完了,但不知道是不是隻有我自己能看懂自己寫的啥。就當練手把。有空把整個專案的實現都寫一遍,複習下也行,感覺不僅文筆差,思路好像也不是很好吧。