总的来说,大多数浏览器有一个单独的处理进程,它由两个任务所共享:JavaScript 任务和用户界面更新任务。每个时刻只有其中的一个操作得以执行。
也就是说当 JavaScript代码运行时用户界面不能对输入产生反应,反之亦然。或者说,当 JavaScript 运行时,用户界面就被“锁定”了。管理好 JavaScript 运行时间对网页应用的性能很重要。
浏览器UI线程
JavaScript 和 UI 更新共享的进程通常被称作浏览器 UI 线程(虽然对所有浏览器来说“线程”一词不一定准确)。此 UI 线程围绕着一个简单的队列系统工作,任务被保存到队列中直至进程空闲。
一旦空闲,队列中的下一个任务将被检索和运行。这些任务不是运行 JavaScript 代码,就是执行 UI 更新,包括重绘和重排版。此进程中最令人感兴趣的部分是每次输入均导致一个或多个任务被加入队列。
<body>
<button οnclick="handleClick()">Click</button>
<script type="text/javascript">
function handleClick(){
var div = document.createElement("div");
div.innerHTML = "Clicked!";
document.body.appendChild(div);
}
</script>
</body>
当例子中的按钮被点击时,它触发 UI 线程创建两个任务并添加到队列中。
第一个任务是按钮的 UI 更新,它需要改变外观以指示出它被按下了,第二个任务是 JavaScript 运行任务,包含 handleClick() 的代码,被运行的唯一代码就是这个方法和所有被它调用的方法。
假设 UI 线程空闲,第一个任务被检查并运行以更新按钮外观,然后 JavaScript 任务被检查和运行。
在运行过程中,handleClick() 创建了一个新的<div>元素,并追加在<body>元素上,其效果是引发另一次 UI 改变。
也就是说在 JavaScript 运行过程中,一个新的 UI 更新任务被添加在队列中,当 JavaScript 运行完之后,UI 还会再更新一次。
当所有 UI 线程任务执行之后,进程进入空闲状态,并等待更多任务被添加到队列中。空闲状态是理想的,因为所有用户操作立刻引发一次 UI 更新。
如果用户企图在任务运行时与页面交互,不仅没有即时的 UI 更新,而且不会有新的 UI 更新任务被创建和加入队列。
事实上,大多数浏览器在 JavaScript 运行时停止 UI 线程队列中的任务,也就是说 JavaScript 任务必须尽快结束,以免对用户体验造成不良影响。
专家指出如果该接口在 100 毫秒内响应用户输入,用户认为自己是“直接操作用户界面中的对象。”超过 100 毫秒意味着用户认为自己与接口断开了。
由于 UI 在 JavaScript 运行时无法更新,如果运行时间长于 100 毫秒,用户就不能感受到对接口的控制。