同步与异步:从阻塞到非阻塞的编程思维跃迁

123 阅读3分钟

同步和异步

学习预知(前言/引言):

在编程世界中,​​同步​​和​​异步​​是两种截然不同的代码执行范式,它们决定了程序如何响应时间消耗操作(如网络请求、文件读写等)。同步代码像一条单行道,必须等待前车通过才能继续前进;而异步代码则像立交桥,通过回调、Promise或事件驱动让程序在等待时依然能处理其他任务。

​学习本文后,你将掌握:​

  1. ​同步的代价​​:理解为何for循环会冻结界面,而setTimeout不会
  2. ​异步的魔力​​:从回调地狱到async/await的进化之路
  3. ​底层机制​​:事件循环如何像调度中心一样管理任务队列
  4. ​实战抉择​​:何时用同步保顺序,何时用异步提性能

​关键认知突破:​

  • 异步不是"同时执行",而是"不必等待"
  • 单线程的JavaScript如何通过事件循环实现高并发
  • PromisesetTimeout在事件循环中的不同命运

准备好颠覆你对程序执行的认知了吗?让我们从一段被setTimeout欺骗的代码开始……

1. 进程:

在不同的场景中都可以用来描述改场景中的一个效果,线程是进程里面的一个更小的单位,通常多个线程配合工作构成一个进程。

  • V8 运行一份 js 代码,会创建一份进程,从上往下执行代码,遇到同步代码直接执行,遇到异步代码就跳过,先去执行后面的同步代码全部执行完毕后再回过头来执行异步代码。

  • js默认是单线程语言:因为 js 的设定是为了做浏览器的脚本语言,尽量少的开销用户的设备的性能

有手段弄成多线程,但是情况很少一般不考虑。

2. 线程

实例

let a = 1              //同步代码
setTimeout(() =>{      //异步代码
   a = 2
   console.log(a,'ZHT');
},1000)
console.log(a);

结果:

a = 1

a = 2 ZHT

  • 其中() =>{ a = 2 console.log(a,'ZHT'); }为回调函数,等里面的进行完了再回过来调用

定时器 setTimeout() 和 setInterval() 的区别,setTimeout() 延迟指定时间后执行​​一次​,单次延迟操作 setInterval() 每隔指定时间​​重复执行​,周期性重复操作

同步:我们把不耗时的代码称为同步代码。

异步: 我们把耗时的代码称为异步代码。

对于 V8 来说只有定时器才会耗时,其余的都不耗时。但是对于计算机的角度的话会根据计算机的性能都耗时。

处理异步

  • 因为 js 的这种执行规则,导致我们在开放过程中的时而会出现代码异步的情况。
  1. 回调函数
function xq() {
  setTimeout(() => {
    console.log('我们去相亲');
    marry()
  }, 1000)
}
function marry() {
  console.log('我们结婚了');
}
xq()

当嵌套过深时,代码的可读性差,维护困难,排查问题困难(回调地狱)

function xq() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('我们去相亲');
      resolve()    //最后一步执行
    }, 2000)
  })
}
function marry() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('我们结婚啦!');
      resolve()
    }, 1000)
  })
}
function baby() {
  setTimeout(() => {
    console.log('我们生小宝宝啦!');
  }, 500)
}
xq()
  .then(() => {
    return marry()
  })
  .then(() => {
    baby()
  })
  • then的源代码里面也返回了一个 promise 实例对象,状态默认继承自 xq 函数返回的对象状态

  • xq() 里面执行到了reslove()后面的 .then才会触发

V8 引擎的原理:

  1. 执行 xq 函数,立即返回一个 promise 实例对象,但是此时该对象的状态是 pending(等待状态)

  2. .then 立即触发,但是 then 里面的回调函数没有触发

  3. 等待 xq 函数里面的 reslove() 执行完毕,此时实例对象的状态会变更为fulfillde(成功状态),此时 .then 里面的回调函数会触发执行