JavaScript 学习笔记 之 异步(一)

分块的程序

JavaScript中的程序是由多个块组成的

程序执行时,只有一个块是现在执行,其他的块都是将来再执行

最简单常见的块单位是函数

我们在写程序的时候可能会经常遇到一个问题

程序中某个块我们并不希望在现在执行的块结束后就立刻执行

比如获取后台的数据的块执行完之后,我们希望当后台的数据接收完毕之后再执行打印出数据的块

而不是一发送完请求就立刻打印

回调函数是最简单的实现方式,但不是唯一的实现方式

Ajax也是个很好的实现方式,ajax发送一个异步请求,然后在将来获取到结果了之后再执行打印数据的块

(尽可能的不要使用同步Ajax请求,因为这样会锁定浏览器UI(按钮,菜单,滚动条等),并阻塞所有的用户交互)

任何时候只要把一段代码包装成一个函数,并指定它在响应某个事件(定时器,鼠标点击,Ajax响应等)时执行,就等于在代码中创建了一个将来的块,也由此引入了异步机制

 

异步控制台

console.*方法组没有什么规范或者需求来指定它们如何工作

控制台并不是JavaScript的一部分,而是由宿主环境(比如说浏览器)添加到JavaScript中的

因此不同的浏览器和JavaScript环境可以根据自己的意愿来实现

尤其要提出,console.log(..)并不会将传入的内容立即输出

因为I/O是非常低速的阻塞部分,浏览器是在后台异步处理控制台I/O的

但是大部分情况下并不会有什么影响

当你发现控制台输出的语句并不是你期望的时候

你可能需要考虑下是不是因为这个原因导致console.log(..)推迟执行了

最好的选择是使用断点来调试,或者用JSON.stringify(..)进行一次"快照"
 

事件循环

JavaScript引擎并不是独立运行的,它允许在宿主环境中(如web浏览器或者Node.js等)

这些环境都提供了一种机制来处理程序中多个块的执行,而且执行每块时调用JavaScript引擎

这种机制就是事件循环

也就是说JavaScript引擎本身没有时间概念,只是一个按需执行JavaScript代码的环境

事件调度是由包含它的环境(比如浏览器)来进行的

那么,什么是事件循环

简单的来说,可以把事件循环看做一个队列(先进先出)

当一个事件执行完后,从队列摘下一个事件并执行,这些事件就是你的回调函数

setTimeout(..)定时器的精度可能不是很高,正是因为setTimeout(..)函数并没有将回调函数挂在事件队列中

而是设定了一个定时器,当定时器到时后,环境会把你的回调函数放在事件循环中

当这时事件循环中有很多个事件在排队等待的时候,这个回调函数得排在其他项目后面

因此执行时间可能会更长

事实上,直到ES6,JavaScript才真正内建有直接的异步概念,在此之前都是由宿主环境来管理的

这个改变一个主要原因是,ES6中Promise的引入精确指定了事件循环的工作细节

并行线程

异步和并行经常会混为一谈,但事实上它们的意义完全不同

异步是关于现在和将来的时间间隙,而并行是能够同时发生的事情

并行最常见的计算工具就是进程和线程

进程和线程独立运行,并可能同时运行:在不同的处理器,甚至不同的计算机上

但多个线程能够共享单个进程的内存

而事件循环不允许对共享内存的并行(同时)访问和修改

完整运行

由于JavaScript的单线程特性

事件中的代码具有完整性

一旦某个事件开始运行了,这个事件中所有的代码都会在下一个事件中任意代码运行之前完成

这称为完整运行特性

竞态条件

JavaScript是单线程编程(不跨线程共享数据),而且有完整运行的特性

这意味着不会出现多线程编程中交错运行导致的不确定行为(语句(表达式运算)顺序级别的不确定性)

但这不表示JavaScript总是确定性的

比如两个ajax请求的回调函数的先后执行顺序

这种函数的不确定性就被称为竞态条件(函数(事件)级别的不确定性)

猜你喜欢

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