sailei1 / blog

1 stars 0 forks source link

你不知道的JS - 异步与回调函数笔记 #80

Closed sailei1 closed 4 years ago

sailei1 commented 4 years ago

JavaScript 程序总是至少分为两个块:第一块现在运行;下一块将来运行,以响 应某个事件。尽管程序是一块一块执行的,但是所有这些块共享对程序作用域和状态的访 问,所以对状态的修改都是在之前累积的修改之上进行的。 一旦有事件需要运行,事件循环就会运行,直到队列清空。事件循环的每一轮称为一个tick。用户交互、IO 和定时器会向事件队列中加入事件。

ajax ajax 请求通常是异步的。虽然可以发送ajax同步请求,但会锁定浏览器UI并阻塞所有用户的交互, 在任何情况下都不应该使用这种方式。

异步控制台 console.log(...) 并不会把传入的内容立即输出,基于浏览器控制台I/O异步化造成的。(I/O是非常低速的阻塞部分) 建议调试的时候 在 JavaScript 调试器中使用断点, 而不要依赖控制台输出

JS 事件循环

JavaScript 引擎本身并没有时间的概念,只是一个按需执行 JavaScript 任意代码 片段的环境。“事件”(JavaScript 代码执行)调度总是由包含它的环境进行。

setTimeout(..)并没有把你的回调函数挂在事件循环队列中。它所做的是设定一个定时器。当定时器到时后,环境会把你的回调函数放在事件循环中。

如果这时候事件循环中已经有20个项目了会怎样呢?你的回调就会等待。它得排在其他项目后面——通常没有抢占式的方式支持直接将其排到队首。

异步是关于现在和将来的时间间隙,而并行是关于能够同时发生的事情。 单线程事件循环是并发的一种形式

协作

取到一个长期运 行的“进程”,并将其分割成多个步骤或多批任务,使得其他并发“进程”有机会将自己 的运算插入到事件循环队列中交替运行。

setTimeout(..0) 并不直接把项目插入到事件循环队列。定时器 会在有机会的时候插入事件。举例来说,两个连续的 setTimeout(..0) 调用 不能保证会严格按照调用顺序处理,所以各种情况都有可能出现,比如定时 器漂移,在这种情况下,这些事件的顺序就不可预测。

任务队列

事件循环队列类似于一个游乐园游戏:玩过了一个游戏之后,你需要重新到队尾排队才能 再玩一次。而任务队列类似于玩过了游戏之后,插队接着继续玩。 任务和 setTimeout(..0) hack 的思路类似,但是其实现方式的定义更加良好,对顺序的保 证性更强:尽可能早的将来

回调函数

回调函数是逻辑控制反转 回调表达程序异步和管理并发的两个主要缺陷:缺乏顺序性和可信任性