错误,能够及时发现线上BUG,助您提升用户体验!
JavaScript程序的构建块
你可能在单个.js文件中编写 JavaScript 应用程序,但可以肯定的是,你的程序由几个块组成,其中只有一个正在执行,其余的将在稍后执行。最常见的块单元是函数。
大多数刚接触JavaScript的开发人员似乎都有这样的问题,就是认为所有函数都是同步完成,没有考虑的异步的情况。如下例子:

你可能知道标准 Ajax 请求不是同步完成的,这说明在代码执行时
Ajax(..)函数还没有返回任何值来分配给变量response。一种等待异步函数返回的结果简单的方式就是 回调函数:

注意:实际上可以设置同步Ajax请求,但永远不要那样做。如果设置同步Ajax请求,应用程序的界面将被阻塞——用户将无法单击、输入数据、导航或滚动。这将阻止任何用户交互,这是一种可怕的做法。
以下是同步 Ajax 地,但是请千万不要这样做:

这里使用Ajax请求作为示例,你可以让任何代码块异步执行。
这可以通过 setTimeout(callback,milliseconds) 函数来完成。setTimeout 函数的作用是设置一个回调函数milliseconds后执行,如下:
function first() { console.log('first'); } function second() { console.log('second'); } function third() { console.log('third'); } first(); setTimeout(second, 1000); // Invoke `second` after 1000ms third();输出:
first third second解析事件循环
这里从一个有点奇怪的声明开始——尽管允许异步 JavaScript 代码(就像上例讨论的setTimeout),但在ES6之前,JavaScript本身实际上从来没有任何内置异步的概念,JavaScript引擎在任何给定时刻只执行一个块。
那么,是谁告诉JS引擎执行程序的代码块呢?实际上,JS引擎并不是单独运行的——它是在一个宿主环境中运行的,对于大多数开发人员来说,宿主环境就是典型的web浏览器或Node.js。实际上,现在JavaScript被嵌入到各种各样的设备中,从机器人到灯泡,每个设备代表 JS 引擎的不同类型的托管环境。
所有环境中的共同点是一个称为事件循环的内置机制,它处理程序的多个块在一段时间内通过调用调用
JS引擎的执行。这意味着JS引擎只是任意JS代码的按需执行环境,是宿主环境处理事件运行及结果。
例如,当 JavaScript 程序发出 Ajax 请求从服务器获取一些数据时,在函数(“回调”)中设置“response”代码,JS引擎告诉宿主环境:"我现在要推迟执行,但当完成那个网络请求时,会返回一些数据,请回调这个函数并给数据传给它"。
然后浏览器将侦听来自网络的响应,当监听到网络请求返回内容时,浏览器通过将回调函数插入事件循环来调度要执行的回调函数。以下是示意图:

这些Web api是什么?从本质上说,它们是无法访问的线程,只能调用它们。它们是浏览器的并发部分。如果你是一个Nojs.js开发者,这些就是 c++ 的 Api。
这样的迭代在事件循环中称为(tick)标记,每个事件只是一个函数回调。

让我们“执行”这段代码,看看会发生什么:
1. 初始化状态都为空,浏览器控制台是空的的,调用堆栈也是空的

2. console.log('Hi')添加到调用堆栈中

3. 执行console.log('Hi')

4. console.log('Hi')从调用堆栈中移除。

5. setTimeout(function cb1() { ... }) 添加到调用堆栈。

6. setTimeout(function cb1() { ... }) 执行,浏览器创建一个计时器计时,这个作为Web api的一部分。

7. setTimeout(function cb1() { ... })本身执行完成,并从调用堆栈中删除。

8. console.log('Bye') 添加到调用堆栈

9. 执行 console.log('Bye')

10. console.log('Bye') 从调用调用堆栈移除

11. 至少在5秒之后,计时器完成并将cb1回调推到回调队列。

12. 事件循环从回调队列中获取cb1并将其推入调用堆栈。

13. 执行cb1并将console.log('cb1')添加到调用堆栈。

14. 执行 console.log('cb1')
关键字:
