在 JS 代码中,异步无处不在,比如 Ajax 通信,Node 中的文件读写等等。而只有搞清楚异步编程的原理和概念,才能在 JS 的世界中任意驰骋,随便撒欢。

单线程 JavaScript 异步方案

首先我们要了解,JavaScript 代码的运行是单线程。

采用单线程模式工作的原因也很简单,最早是为了在页面中实现 Dom 操作。如果采用多线程,就会造成复杂的线程同步问题。如果一个线程修改了某个元素,另一个线程又删除了这个元素,浏览器渲染就会出现问题。

单线程的含义就是,JS 执行环境中负责执行代码的线程只有一个。类似于只有一个人干活。他一次只能做一个任务,如果有多个任务自然是要排队的。

优点:安全,简单。

缺点:遇到任务量大的操作,会阻塞。后面的任务会长时间等待,出现假死的情况。

异步无处不在:同步模式和异步模式(一)_同步模式

为了解决阻塞的问题,Javascript 将任务的执行模式分成了两种,同步模式( Synchronous)和 异步模式( Asynchronous)。

同步模式与异步模式

在程序中,代码依次执行,后面的任务需要等待前面任务执行结束后,才会执行。同步并不是同时执行,而是排队执行。

先来看一段代码:

console.log('global begin')
function bar () {
  console.log('bar task')
}
function foo () {
  console.log('foo task')
  bar()
}
foo()
console.log('global end')复制代码

用动画形式展现下同步代码的执行过程:

异步无处不在:同步模式和异步模式(一)_同步模式_02

如图所示,代码会按照既定的语法规则,依次执行。如果中间遇到大量复杂任务,后面的代码则会阻塞等待。

再来看一段异步代码:

console.log('global begin')

setTimeout(function timer1 () {
  console.log('timer1 invoke')
}, 1800)

setTimeout(function timer2 () {
  console.log('timer2 invoke')
  setTimeout(function inner () {
    console.log('inner invoke')
  }, 1000)
}, 1000)

console.log('global end')复制代码

异步代码的执行,要相对复杂一些。

异步无处不在:同步模式和异步模式(一)_同步模式_03

代码首先按照同步模式执行,当遇到异步代码时,会开启异步执行线程。

在上面的代码中,setTimeout 会开启环境运行时的执行线程运行相关代码。代码运行结束后,会将结果放入到消息队列,等待 JS 线程结束后,消息队列的任务再依次执行。

流程图如下:

异步无处不在:同步模式和异步模式(一)_同步模式_04

下篇,我们来聊聊回调函数和异步方案(ง •_•)ง。