-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JavaScript的单线程机制 #15
Comments
看懂了,写得非常好。 |
Yes, I get it. |
good job! |
我执行了下代码,0 |
@guwenbin1991 那是因为你是5秒后才点击的吧 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
一道面试题
之前有次面试的时候,被问到一个有关单线程的问题,后来整理了一下,增加了一些复杂度。
如果你能很清晰的判断输出结果,并且没有疑惑,那说明你对 JavaScript 的单线程理解的不错,这篇文章没有看的必要了,如果不清楚,请继续看下去。
执行机制
JavaScript 是一门单线程语言,即同一时间只能执行一段代码。所以,对于同步任务,后一个任务只能等前一个任务处理完才能被执行。
然而,借助于事件驱动机制,JavaScript 可以通过异步任务去处理耗时比较长的操作,比如 Ajax 请求数据这种。再通过回调,将这些操作变成异步,放在异步的任务队列里执行,从而避免 JavaScript 执行线程的阻塞。
总结下来,JavaScript 对任务的处理机制是:
只有在执行线程空闲的情况下,才会去执行异步任务队列中的任务(其中事件会优先执行)。
定时器
定时事件也是会被放在异步任务队列中的一类事件,用来指定某些代码在多少时间后执行。
有两个函数可以实现定时功能,一个是
setTimeout
,一个是setInterval
,两者机制相同,区别是前者是一次性执行,后者反复执行。它们都接受两个参数,第一个是回调函数,第二个是延迟毫秒数。后面的讲解以setTimeout
为例。前面 JavaScript 执行机制小节中提到,
setTimeout
只是在设定时间到了后,将回调放入异步任务队列,而不是立即执行。因此,回调执行的时间是大于等于实际设定的毫秒数的。如果将延迟时间设为 0 ,即
setTimeout(fn, 0)
,表示在执行线程空闲后,立即执行指定回调 fn,但这个回调要等任务队列中处于等待状态的事件处理程序全部执行完后,才会“立即”调用。这一点在《JavaScript 权威指南》 14.1 计时器小节中有提到。setTimeout(fn, 0)
的主要作用是,改变了代码流程,把 fn 的执行放在了当前同步代码全部执行完之后。另外,在 HTML5 规范中 setTimeout 的延时的最小值为 4 毫秒。
浏览器不是单线程的
虽然 JS 的执行是单线程的,但浏览器并不是单线程,而是通常有以下四种:
因此,在 Ajax 请求时,浏览器会新开一个线程来请求,在请求的状态变更时,将相应的回调放入异步任务队列,在执行线程空闲的时候,Event Loop 开始。
题目解析
文章开头那道题的答案是这样的:
下面简单分析一下:
首先,同步任务按先后顺序最先执行,耗时比较长的同步任务会阻塞当前线程,
6-8
行、24
行和25
行的输出没有疑问。对应输出1-7
行。然后,在执行线程工作的时候,
1-4
行定时器产生的回调、10-12
行定时器产生的回调和两次 click 对应的回调被先后放入异步任务队列。由于执行线程空闲后,在进行 Event Loop 的时候,会先查看是否有事件可执行,接着再处理其他异步任务。因此会产生8-11
行这样的输出顺序。最后,5s 后的两次 click 事件被放入异步任务队列,由于此时执行线程为空,便被立即执行了。对应输出
12-13
行。参考
The text was updated successfully, but these errors were encountered: