JavaScript 学习笔记 之 异步(二)

并发

我们在开发过程中经常会遇到的一个情况是,两个事件同时执行

比如在实现一个懒加载的界面的时候

用户滚动页面,触发一个ajax请求

当用户滚动页面足够快的时候

发起一个ajax请求的事件可能会与返回ajax响应的事件同时(同一时间段内,并不需要在同一时刻)执行

像这样(至少)两个事件或者说"进程"同时执行就出现了并发

但在JavaScript中,它们的事件是在事件循环队列中依次运行的

单线程事件循环是并发的一种形式

非交互

当并发执行的多个"进程"在同一个程序内的任务彼此不相关时

就不一定需要交互

因为进程间没有相互影响,执行的先后顺序带来的不确定性是完全可以接收的

交互

更常见的情况是需要交互进行协调来避免竞争态的出现

比如A进程对data进行+1操作

B进程对data进行*2操作

这时候先执行A进程和先执行B进程会导致结果很大的不同

这种不确定性就是一个竞态bug

所以我们可以通过协调交互顺序来处理这样的bug

例如设定一些判断条件来确保运行顺序

协作

还有一种并发合作方式,成为并发协作

这里的目标是取到一个长期运行的"进程"

将其分割为多个步骤或者多批任务

使得其他并发"进程"有机会进入到事件循环中

例如一个运算量非常庞大的进程

需要处理1000万条数据

这样的进程运行时,其他代码都不能运行,包括不能有其他的函数调用或者UI刷新

甚至连滚动,输入,点击之类的用户事件也无法运行

因此我们可以将这个进程分成很多份

一次只处理1000条数据

然后利用setTimeout(..0)(hack)进行异步调度

也就是下一次处理事件放在当前事件循环的结尾处

来确保事件循环中其他事件能够运行

严格来说,setTimeout(..0)并不直接把项目插入到事件循环队列,而是在有机会的时候插入

因此两个连续的setTimeout(..0)并不能保证严格按照调用顺序处理

比如定时器漂移,在这种情况下,这些事件的顺序就不可预测

在Node.js中类似的方法是process.nextTick(..)

尽管他们使用方便,但是没有直接的方法能够适应所有的环境来确保异步事件的顺序

任务

在ES6中,有一个新的概念建立在事件循环队列之上,叫做任务队列

这个概念带来的最大影响可能是Promise的异步特性

举个简单的例子来说明这两者的区别

事件循环队列类似于排队排到队尾的队列

而任务队列类似于直接插队的一个队列

任务和setTimeout(..0)hack的思路类似,但是对顺序的保证性更强:尽可能早的到来(也就是插队)

猜你喜欢

转载自blog.csdn.net/Aproducer/article/details/82934518