本文的内容非常适合 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 提供了一种方便快捷的并发编程方式,以及一套处理返回值和错误值的规范。在理解和熟悉了这种规范之后,可以大大提高我们处理并发任务的效率。