web worker 是運行在后臺的 JavaScript,獨立于其他腳本,不會影響頁面的性能。這是HTML5的1個標準;實現上講,閱讀器為wokrer啟動了新的線程,從而實現了異步操作的功能;
下面是woker的1個簡單例子,在html頁面中,以worker.js為源文件,創建了名為“worker”的Worker對象,通過worker.postMessage()接口向worker線程發送消息; worker線程將JSON格式化傳遞的兩個數據相加后,再通過postMessage()接口將消息發送回頁面js運行的主線程; 主線程再在onMessage()函數中處理woker線程發來的消息;
main.html
WebKit加載并履行js的流程簡單分成以下幾步:
1. 履行到"var worker = new Worker('worker.js')“時,在內核中構造WebCore::JSWorker對象(JSBbindings層)和對應的WebCore::Worker對象(WebCore模塊);
2. 構造JSWorker對象的進程中,根據初始化的url地址"worker.js"發起異步加載的流程;
3. 履行worker.postMessage(),向worker線程發送JSON格式化的消息數據; 由于這個時候,worker線程還沒有創建,所以消息數據放在1個臨時消息隊列中;
4. worker.js異步加載完成后,創建并啟動worker線程,并將臨時消息隊列中的消息數據copy到woker對應的WorkerRunLoop的消息隊列中;
5. worker線程創建完成后,開始處理WorkerRunLoop的消息隊列中所保存的消息;
6. woker線程發送消息到主線程;
7. 主線程收到worker線程發送的消息,履行onMessage();
在經過1輪消息來回后,我們如果通過例子中button按鈕來異步觸發消息發送,那末步驟3的履行會有區分; 這個時候由于worker線程已創建,所以消息會直接添加到WorkerRunLoop的消息隊列中;
為了弄清楚全部實現機制,我們先來看1下WebKit內部worker相干的類, 其中Worker對應主頁面JS中的'worker'對象(主線程中),而DedicatedWorkerThread表示worker線程; WorkerMessagingProxy關聯了Worker對象與worker線程,從而實現主線程與worker線程之間的消息中轉; DedicatedWorkerThread通過WorkerScriptController控制worker.js文件中的腳本在worker線程中的履行;閱讀器會為worker線程創建1個獨立的虛擬機環境(VM);
下面來看1下詳細流程:
1. worker.js的異步加載進程以下圖,加載是在創建WebCore::JSWorker和WebCore::Worker對象的時候發起的,并且是異步加載的流程,不會阻塞后續JS的履行,這也是為何首次調用worker.postMessage()的時候,會出現worker線程還沒有創建的情況;
2. worker線程的創建以下圖所示。可以看出,當worker.js加載完成后,WebKit會通過中轉對象WorkerMessagingProxy創建DedicatedWorkerThread對象,并啟動WorkerThread; WorkerMessagingProxy保持DedicatedWorkerThread對象的指針;
3. 主線程向worker線程發送消息的流程以下,當js履行到"worker.postMessage()“時,終究會通過JS主線程虛擬機映照到JSWorker::postMessage()函數,并通過中轉對象WorkerMessagingProxy將消息添加到worker的消息隊列; 如果worker線程在發送消息的時候,還沒有創建,我們看到有個m_queueEarlyTasks對象會臨時保存當前消息,并在worker線程創建后再轉移到正式的消息隊列中; 否則,直接將消息添加到WorkerRunLoop管理的正式消息隊列中;
4. worker線程中處理消息的流程以下,這就是worker.js中開始履行”onmessage()”的流程; 我們可以看到DedicatedWorkThread對象在自己的線程環境下的runLoop取出消息隊列中的數據履行;而履行是通過EventTarget::dispatchEvent()分發并fire1個"message"類型的事件來實現的;
.
5. 下圖是在worker線程中發送消息的流程,也是通過WorkerMessagingProxy來進行中傳,最后會觸發Document::postTask()函數,該函數實際上將Document::didReceiveTask()函數拋到主線程上去履行;
6. 下圖是main線程上處理消息的流程, Document::didReceiveTask()在主線程上開始履行,終究也是通過dispatch并fire1個"message"類型的事件實現消息的處理;
,
所以總得來說,woker的機制是通過中轉對象實現消息的傳遞,再通過"message"事件完成消息的處理;
(轉載請注明出處:http://blog.csdn.net/codigger)