原文: 《JavaScript Visualized: Event Loop》 - By Lydia Hallie
本文主要经过生动形象的动图讲解事件循环的一些基本概念,主要面向初学者,译者已取得原做者的赞成。本文一些部分采用意译,以帮助你们更好地理解。
本文首发于我的博客 Logan's Blog,其余JS相关内容也可前往小弟博客共同窗习探讨。javascript
事件循环(Event Loop),是每一个JS开发者都会接触到的概念,可是刚接触时可能会存在各类疑惑。我是一个视觉型学习者,因此打算经过gif动图的可视化形式帮助你们理解它。java
首先咱们来看看,什么是事件循环,咱们为何要了解它呢?git
众所周知,JavaScript是 单线程(single-threaded) 的,也就是同一时间只能运行一个任务。通常状况下这并无什么问题,可是假如咱们要运行一个耗时30秒的任务,咱们就得等待30秒后才能执行下一个任务(这30秒期间,JavaScript占用了主线程,咱们什么都不能作,包括页面也是卡死状态)。这都9012年了,不带这么坑爹的吧?github
好在浏览器向咱们提供了JS引擎不具有的特性:Web API
。Web API
包括DOM API
、定时器
、HTTP请求
等特性,能够帮助咱们实现异步、非阻塞的行为。浏览器
当咱们调用一个函数时,函数会被放入一个叫作调用栈(call stack,也叫执行上下文栈)的地方。调用栈是JS引擎的一部分,并不是浏览器特有的。调用栈是一个栈数据结构,具备后进先出的特色(Last in, first out. LIFO)。当函数执行完毕返回时,会被弹出调用栈。数据结构
图例中的respond
函数返回一个setTimeout
函数调用,setTimeout
函数是Web API
提供给咱们的功能:它容许咱们延迟执行一个任务而不用阻塞主线程。setTimeout
被调用时,咱们传入的回调函数,即箭头函数() => { return 'hey' }
会被传递给Web API
处理,而后setTimeout
和respond
依次执行完毕出栈。异步
在Web API
中会执行定时器,定时间隔就是咱们传入setTimeout
的第二个参数,也就是1000ms。计时结束后回调函数并不会当即进入调用栈执行,而是会被加入一个叫作 任务队列(Task Queue) 的地方。函数
看到这里,有些人可能会疑惑:1000ms以后,回调居然没有放入调用栈执行,而是被放入了任务队列,那何时被执行呢?不要急,既然是一个队列,那就要排排坐,吃果果。oop
接下来就是咱们期待已久,万众瞩目的 事件循环(Event Loop) 闪亮登场的时刻了。Event Loop的工做就是链接任务队列和调用栈,当调用栈中的任务均执行完毕出栈,调用栈为空时,Event Loop会检查任务队列中是否存在等待执行的任务,若是存在,则取出队列中第一个任务,放入调用栈。学习
咱们的回调函数被放入调用栈中,执行完毕,返回其返回值,而后被弹出调用栈。
阅读一时爽,但只有经过反复练习,将其变为本身的东西后才会一直爽。咱们来作个小练习检测下学习成果,看看下面代码输出什么:
const foo = () => console.log('First');
const bar = () => setTimeout(() => console.log('Second'), 500);
const baz = () => console.log('Third');
bar();
foo();
baz();
复制代码
相信你们均可以轻松给出正确答案。咱们一块儿来看下这段代码运行时发生了什么:
bar
被调用,返回setTimeout
的调用;setTimeout
的回调被传递给Web API
处理,setTimeout
执行完毕出栈,bar
执行完毕出栈;foo
被调用,打印First
,foo
执行完毕出栈;baz
被调用,打印Third
,baz
执行完毕出栈;Second
,执行完毕出栈。但愿本文能帮助你对事件循环有一个初步的了解,若是还有疑惑,可留言交流探讨。