什么是Promise

Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理和更强大。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
(1)Promise的实例有三个状态:
Pending(进行中)
Resolved(已完成)
Rejected(已拒绝)
当把一件事情交给promise时,它的状态就是Pending,任务完成了状态就变成了Resolved、没有完成失败了就变成了Rejected。
(2)Promise的实例有两个过程:
pending -> fulfilled : Resolved(已完成)
pending -> rejected:Rejected(已拒绝)
需要注意:一旦从进行状态变成为其他状态就永远不能更改状态了。
特点:

  • 将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。流程更加清晰,代码更加优雅。
  • Promise对象提供统一的接口,使得控制异步操作更加容易。

缺点:

  • 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

实例:
当我们在构造 Promise 的时候,构造函数内部的代码是立即执行的:

  1. new Promise((resolve, reject) => {
  2. console.log('new Promise')
  3. resolve('success')
  4. })
  5. console.log('finifsh')
  6. // new Promise -> finifsh

Promise 实现了链式调用,也就是说每次调用 then 之后返回的都是一个 Promise,并且是一个全新的 Promise,原因也是因为状态不可变。如果你在 then 中 使用了 return,那么 return 的值会被 Promise.resolve() 包装

  1. Promise.resolve(1)
  2. .then(res => {
  3. console.log(res) // => 1
  4. return 2 // 包装成 Promise.resolve(2)
  5. })
  6. .then(res => {
  7. console.log(res) // => 2
  8. })

当然了,Promise 也很好地解决了回调地狱的问题,可以把之前的回调地狱例子改写为如下代码:

  1. ajax(url)
  2. .then(res => {
  3. console.log(res)
  4. return ajax(url1)
  5. }).then(res => {
  6. console.log(res)
  7. return ajax(url2)
  8. }).then(res => console.log(res))

前面都是在讲述 Promise 的一些优点和特点,其实它也是存在一些缺点的,比如无法取消 Promise,错误需要通过回调函数捕获。

Promise基础

1、下面代码的执行结果是

  1. const promise = new Promise((resolve, reject) => {
  2. console.log(1);
  3. console.log(2);
  4. });
  5. promise.then(() => {
  6. console.log(3);
  7. });
  8. console.log(4);

最后应该输出1 2 4。这样最主要的就是3,要知道promise.then是微任务,会在所有的宏任务执行完之后才会执行,同时需要promise内部的状态发生变化,因为这里内部没有发生变化,所以不输出3。
2、下面代码的执行结果是

  1. const promise1 = new Promise((resolve, reject) => {
  2. console.log('promise1')
  3. resolve('resolve1')
  4. })
  5. const promise2 = promise1.then(res => {
  6. console.log(res)
  7. })
  8. console.log('1', promise1);
  9. console.log('2', promise2);

输出结果如下:

  1. 'promise1'
  2. '1' Promise{<resolved>: 'resolve1'}
  3. '2' Promise{<pending>}'
  4. 'resolve1'

需要注意的是,直接打印promise1,会打印出它的状态值和参数。
这里说一下这道题的具体思路:

  • script是一个宏任务,按照顺序执行这些代码
  • 首先进入Promise,执行该构造函数中的代码,打印promise1
  • 碰到resolve函数, 将promise1的状态改变为resolved, 并将结果保存下来
  • 碰到promise1.then这个微任务,将它放入微任务队列
  • promise2是一个新的状态为pending的Promise
  • 执行同步代码1, 同时打印出promise1的状态是resolved
  • 执行同步代码2,同时打印出promise2的状态是pending
  • 宏任务执行完毕,查找微任务队列,发现promise1.then这个微任务且状态为resolved,执行它。

这样,就执行完了所有的的代码。
3、下面代码的执行结果是

  1. const promise = new Promise((resolve, reject) => {
  2. console.log(1);
  3. setTimeout(() => {
  4. console.log("timerStart");
  5. resolve("success");
  6. console.log("timerEnd");
  7. }, 0);
  8. console.log(2);
  9. });
  10. promise.then((res) => {
  11. console.log(res);
  12. });
  13. console.log(4);
  • 首先遇到Promise构造函数,会先执行里面的内容,打印1
  • 遇到steTimeout,它是一个宏任务,被推入宏任务队列
  • 接下继续执行,打印出2
  • 由于Promise的状态此时还是pending,所以promise.then先不执行
  • 继续执行下面的同步任务,打印出4
  • 微任务队列此时没有任务,继续执行下一轮宏任务,执行steTimeout
  • 首先执行timerStart,然后遇到了resolve,将promise的状态改为resolved且保存结果并将之前的promise.then推入微任务队列,再执行timerEnd
  • 执行完这个宏任务,就去执行微任务promise.then,打印出resolve的结果

4、 下面代码的执行结果是

  1. Promise.resolve().then(() => {
  2. console.log('promise1');
  3. const timer2 = setTimeout(() => {
  4. console.log('timer2')
  5. }, 0)
  6. });
  7. const timer1 = setTimeout(() => {
  8. console.log('timer1')
  9. Promise.resolve().then(() => {
  10. console.log('promise2')
  11. })
  12. }, 0)
  13. console.log('start');

这个题目就有点绕了,下面来梳理一下:

  • 首先,Promise.resolve().then是一个微任务,加入微任务队列
  • 执行timer1,它是一个宏任务,加入宏任务队列
  • 继续执行下面的同步代码,打印出start
  • 这样第一轮的宏任务就执行完了,开始执行微任务,打印出promise1
  • 遇到timer2,它是一个宏任务,将其加入宏任务队列
  • 这样第一轮的微任务就执行完了,开始执行第二轮宏任务,指执行定时器timer1,打印timer1
  • 遇到Promise,它是一个微任务,加入微任务队列
  • 开始执行微任务队列中的任务,打印promise2
  • 最后执行宏任务timer2定时器,打印出timer2
    1. 'start'
    2. 'promise1'
    3. 'timer1'
    4. 'promise2'
    5. 'timer2'
    这个题目还是比较复杂的,值得去认真理解一下。
    5、 下面代码的执行结果是
    1. const promise = new Promise((resolve, reject) => {
    2. resolve('success1');
    3. reject('error');
    4. resolve('success2');
    5. });
    6. promise.then((res) => {
    7. console.log('then:', res);
    8. }).catch((err) => {
    9. console.log('catch:', err);
    10. })
    执行结果为:then:success1
    这个题目考察的就是Promise的状态在发生变化之后,就不会再发生变化。开始状态由pending变为resolve,说明已经变为已完成状态,下面的两个状态的就不会再执行,同时下面的catch也不会捕获到错误。