怎么理解 Javascript 是单线程,浏览器是多线程?
浏览器内核是多线程的,(浏览器为每个 TAB 页面单独启用进程。进程与线程的关系),通常由以下常驻线程组成
GUI 渲染线程
JavaScript 引擎线程
定时器触发线程
事件触发线程
异步 http 请求线程
Javascript 是单线程的,因为 Js 需要操作 DOM 树,如果是多线程的操作 DOM,可能会出现 UI 操作冲突
怎么记录代码运行时间?
可以通过原生的 Date 对象来跟踪代码的运行时间
var start = + Date()
//(+)可以将Date对象转化为数字
怎么使用定时器分解任务,并增加时间检测机制来改进?
var todo = item.concat()
// 克隆原数组
setTimeout(function() {
// 获取数组的下个元素并处理
process(todo.shift())
// 如果还有需要处理的元素,则创建另一个定时器
if (todo.length > 0) {
setTimeout(arguments.callee, 25)
} else {
callback(items)
}
},25)
有的时候只执行一个任务的效率不高,例如:如果处理一个长度为 1000 项的数组,每处理一项需要 1 毫秒,如果每个定时器只处理一项,且在两次处理之间产生 25 毫秒的延时,数组处理的总时间为 (25+1)x 1000 毫秒,如果修改成一次处理 50 个,处理时间为(1000/50) *25 + 1000 = 1500 毫秒,比单个处理更快。
function timedProcessArray(items, process, callback) {
var todo = items.concat()
setTimeout(function () {
// 这里不能使用箭头函数 因为箭头函数没有arguments
var start = +new Date()
do {
process(todo.shift())
// 处理完后检测时间,如果所用时间小于50毫秒继续处理
} while(todo.length > 0 && (+new Date() - start < 50))
if(todo.length > 0 ) {
setTimeout(arguments.callee, 25)
} else {
callback()
}
},25)
}
定时器对性能有影响吗?
上述的代码使用了定时器序列,同一时间只有一个定时器存在,只有在定时器结束才会创建下一个,这种使用方式不会导致性能问题。
当多个重复定时器同时创建会出现问题,所有的定时器都在争夺运行时间;间隔在 1 秒或 1 秒以上的低频率重复定时器不会出现问题,当在 100 到 200 毫秒间的多个重复定时器会出现问题。
因此应该用一个独立的重复定时器,每次执行多个操作。
总结
JavaScript 任务不应该执行过多的时间(100 毫秒),否则会使 UI 更新出现延迟,影响用户体验
定时器可以让代码延迟执行,可以把长时间运行的代码分解成多个短时间的代码
关于事件循环
事件循环是主线程从任务队列中读取事件,这个过程是循环不断的,被称为事件循环。
主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部 API,它们在”任务队列”中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取”任务队列”,依次执行那些事件所对应的回调函数。
其中定时器事件就是放在任务队列中,setTimeout(fn,100)的含义是。它 100 毫秒后在”任务队列”的尾部添加一个事件,因此要等到同步任务和”任务队列”现有的事件都处理完,才会得到执行。所以并没有办法保证,回调函数一定会在 setTimeout()指定的时间执行。
HTML5 标准规定了 setTimeout()的第二个参数的最小值(最短间隔),不得低于 4 毫秒,如果低于这个值,就会自动增加。