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)