真没那么难!理解 Promise,只需要看这一道题

105 阅读3分钟

本文的内容非常适合 Javascript 的初学者,会用尽量浅显易懂的语言来描述,不用担心看不懂。

Promise,你因何存在?

Promise 是学习现代 Javascript 语言绕不开的知识点。很多人在看的时候会感觉云里雾里,最主要的原因可以概括成一句话:

代码的执行顺序不再是从上到下

正常我们写的代码,是按顺序执行的,比如我们写一段从1数到3的代码。

console.log(1)
console.log(2)
console.log(3)

按下 F12 打开我们浏览器的控制台,把上面的代码复制进去,按下回车,就可以看到数字1到3被按顺序打印了出来。

1
2
3

现在如果我们有这样一个要求,不能改变代码的顺序,但是最后打印的顺序要与代码顺序无关。能做到吗?我们不妨大胆设想,如果1,2,3是分别由三个人来打印,那就很简单了,我们只要同时告诉他们打印数字的任务,这样打印出来的顺序就只和任务的执行时间有关。

Promise 的神奇妙用

那么,怎么把打印的任务分给三个人呢?这里就要用到 Promise 了。通过新建一个 Promise 对象,我们可以让一段代码不在当前的“进程”上执行,而是分配给一个新的“进程”去执行。注意这里的“进程”并不等同于我们常说的操作系统进程,而只是一个抽象的概念,表示一个按顺序执行代码的虚拟单位。

Promise 组装说明书

刚才我们说了,Promise 可以看作是一个新的“进程”,那么我们想让它执行什么代码,就包在一个函数里面交给它。这样,这些代码就不会马上执行。

Promise 还为我们提供了两个函数,一个是 resolve,一个是 reject,我们可以分别在任务完成和任务失败的时候调用。这两个函数是以参数的形式传递到 Promise 的内部的。所以,我们可以这样组装一个 Promise:

new Promise(
  (resolve, _reject) => {
    setTimeout(() => {
      console.log(1)
      resolve()
    }, 300)
  }
)

这里我们用到了 setTimeout 来模拟一个比较耗时的任务,在实际场景中,这个任务可能是读取一个文件,请求一个网络接口,或者是等待用户的输入。在任务完成的时候,我们调用resolve函数来表示任务已经完成。

完整代码

接着,如法炮制,我们组装另外两个 Promise 的时候,只需要提供给它们不同的打印数字,以及任务需要的时间。最后,完整的代码是这样的,你可以试试复制到控制台里试一试。

new Promise(
  (resolve, _reject) => {
    setTimeout(() => {
      console.log(1)
      resolve()
    }, 300)
  }
)
new Promise(
  (resolve, _reject) => {
    setTimeout(() => {
      console.log(2)
      resolve()
    }, 200)
  }
)
new Promise(
  (resolve, _reject) => {
    setTimeout(() => {
      console.log(3)
      resolve()
    }, 100)
  }
)

最终,打印数字的顺序是与任务的执行时间相关:

3
2
1

Promise 与并发模型

并发编程就是如何在有限的CPU核心上,模拟同时执行大量任务的问题。Promise 为 Javascript 提供了一种方便快捷的并发编程方式,以及一套处理返回值和错误值的规范。在理解和熟悉了这种规范之后,可以大大提高我们处理并发任务的效率。