重学前端-Promise用法详解

6,623 阅读6分钟

前言

在JavaScript的世界中,Promise毫无疑问是里程碑式的一个变革,它不仅解决了异步编程中,回调函数嵌套过深的问题,还为Async/Await奠定了基础。

Promise规范最早由CommonJS社区提出,后来成为ES2015(ES6)语言规范,到现在可以说已经成了异步编程的首选方案。
接下来本文将详细讲解Promise的特性和方法,供各位大大们参考,如果文中有不正确的地方,欢迎大家斧正。
话不多说,上才艺!

正文

1、构造函数Promise(excutor)

  • excutor:
    • Promise构造函数接受一个执行器作为参数(excutor,其实就是一个回调函数),在Promise构造函数执行时,会立即执行传入的excutor。
    • excutor函数被调用时,会传入resolve, reject两个函数作为参数;当resolve函数被调用,Promise状态变更为fulfilled(完成);当reject函数被调用,Promise状态变更为rejected(失败)
    • 如果excutor内部抛出异常,Promise状态将直接变更为rejected,错误对象将作为结果返回。
const p = new Promise((resolve, reject) => {
  console.log("excutor函数会被立即执行");
  resolve("状态变更为:fulfilled");
  // reject("状态变更为:rejected");
  // throw new Error('报错,Promise状态将直接变更为rejected')
});

2、状态

Promise一共有3中状态:

  • **pending: **初始状态,既不是成功,也不是失败
  • **fulfilled: **成功
  • rejected: 失败

3、实例方法

- then(onFulfilled, onRejected)

  • 作用:
    • 为Promise注册onFulfilled和onRejected回调
    • 返回新的promise,实现链式调用
    • 新的promise将以回调函数返回值来resolve
  • 特性:
    • then方法本身会自动返回一个新的Promise对象,当然也可以手动在任意(onFulfilled或者onRejected)回调函数中返回一个Promise对象
const p = new Promise((resolve, reject) => {
  console.log("excutor函数会被立即执行");
  resolve("状态变更为:fulfilled");
});

// then方法本身会返回一个promise
p.then()
  .then()
  .then((res) => {
    console.log(res); //输出:状态变更为:fulfilled
  });
// then方法通过回调函数可以返回promise
p.then(
  (res) => {
    return new Promise((resolve, reject) => {
      resolve("onFulfilled中返回的Promise");
    });
  },
  (reason) => {
    return new Promise((resolve, reject) => {
      resolve("onRejected回调中也可以返回Promise");
    });
  }
).then((res) => {
  console.log(res);
});
  • then方法可以通过返回的Promise对象,实现链式调用
  • 如果回调函数返回的是普通值,那么将会在下一个then中作为回调函数参数被接收
  • 如果回调函数返回的是一个Promise, 下一个then方法将会等待这个Promise执行结束,并接收Promise的执行结果
const p2 = new Promise((resolve, reject) => {
  console.log("excutor函数会被立即执行");
  resolve("状态变更为:fulfilled");
});
p2.then(res => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('promise执行完毕')
    }, 1000);
  })
}).then(res => {
  console.log(res)//等待1秒钟,输出:promise执行完毕
})
  • 如果没有传入回调函数,Promise将自动为then方法注册回调函数,并在回调函数中将接收到的值返回,传递给下一个then,实现值的穿透。
没有给then注册回调,发生值穿透
const p3 = new Promise((resolve, reject) => {
  resolve(1);
});
p3.then(2).then(4).then(console.log); //1

  • then方法中不允许将本身返回的promise对象作为返回值
const p4 = p3.then(res => {
  // 不允许,将会报错
  // TypeError: Chaining cycle detected for promise #<Promise>
  return p4
})

- catch(onRejected)

  • 作用
    • 给Promise添加onRejected回调
  • 特性
    • 返回一个新的Promise
    • 新的Promise将以回调函数返回值来resolve
const promise = new Promise((resolve, reject) => {
  reject(100);
});
promise
  .catch((reason) => {
    console.log(reason); //100
    return 200; //catch函数返回值将作为新Promise的resolve结果
  })
  .then((res) => {
    // 新Promise执行结果
    console.log(res); //200
  });

- finally(finallyCallback)

  • 作用
    • 给Promise添加一个事件处理回调函数
  • 特性
    • 无论成功还是失败,都会调用传入的finallyCallback
    • finallyCallback会返回一个新的Promise
    • finallyCallback内部不能获取到Promise执行结果
const promise = new Promise((resolve, reject) => {
  resolve(100);
});
promise
  .finally((res) => {
    console.log("finally回调函数无论成功或者失败,始终会被执行");
    // finally回调函数内获取不到promise执行结果
    console.log(res);
  })
  .then((res) => {
    // finally回调函数返回一个新的promise,实现链式调用
    console.log(res);
  });

4、静态方法

- Promise.all(promiseArray)

  • 作用:
    • 接受一个数组作为参数,将执行结果以数组形式顺序返回
    • 并发执行数组中的promise对象
  • 特性:
    • 接受一个数组作为参数,数组元素可以是普通值,也可以是promise对象
    • 执行结果以数组形式返回,数组中元素跟传入的promiseArray一一对应
    • 如果传入的数组中元素是普通值,直接原样将对应值放入结果数组中
    • 如果传入的数组中元素是promise对象,将并发执行对应的Promise对象,并等待执行结束,返回结果
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p1");
  }, 2000);
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2");
  }, 1000);
});

const promiseAll = Promise.all([1, 2, promise1, 3, 4, promise2, 5]);
promiseAll.then((res) => {
  //并发执行promise
  //执行结果与传入的数组一一对应
  //会等待所有任务执行完毕之后统一返回结果
  console.log(res); //[1,2,"p1",3,4,"p2",5]
});
  • 如果传入的数组中某一项执行失败,那么Promise将会执行失败
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p1");
  }, 2000);
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('我这该死的温柔,居然执行失败了')
  }, 1000);
});

const promiseAll = Promise.all([1, 2, promise1, 3, 4, promise2, 5]);
promiseAll.then((res) => {
  // 任何一个任务执行失败 ,整个promise将执行失败
  console.log(res);
}).catch(e => {
  //任何一个任务失败,将导致整个Promise执行失败
  console.log('fail',e)
});

- Promise.allSettled(promiseArray)

非正式版,目前处于stage4阶段,尚未完全被浏览器支持

  • 作用:
    • 同Promise.all
  • 特性:
    • 等待数组中所有任务执行完毕,返回一个数组
    • 无论成功还是失败,都会有返回结果
    • 其它同Promise.all
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p1");
  }, 2000);
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("我这该死的温柔,居然执行失败了");
  }, 1000);
});

const promiseAll = Promise.allSettled([1, 2, promise1, 3, 4, promise2, 5]);
promiseAll
  .then((res) => {
    /**
     Promise.allSettled执行结果
    [
      { status: 'fulfilled', value: 1 },
      { status: 'fulfilled', value: 2 },
      { status: 'fulfilled', value: 'p1' },
      { status: 'fulfilled', value: 3 },
      { status: 'fulfilled', value: 4 },
      { status: 'rejected', reason: '我这该死的温柔,居然执行失败了' },
      { status: 'fulfilled', value: 5 }
    ]
   */
    console.log(res);
  })
  .catch((e) => {
    console.log("fail", e);
  });

- Promise.race(promiseArray)

  • 作用
    • 接受一个数组, 并发执行数组中的任务
    • 谁执行块,就返回谁的结果,无论成功还是失败
    • 一般用来做网络超时功能
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p1");
  }, 2000);
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2");
  }, 1000);
});
const promise3 = new Promise((resolve, reject) => {
  // 假设500毫秒后网络超时
  setTimeout(() => {
    reject("超时了");
  }, 500);
});

const promiseRace = Promise.race([promise1, promise2, promise3]);
promiseRace
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    // 谁执行块,就返回谁
    console.log("fail", e);
  });

- Promise.reject(reason)

  • 作用:
    • 返回一个状态为失败的Promise,并将失败信息传递给对应的处理方法
Promise.reject("rejected")
  .then((res) => {
    console.log('value', res);
  })
  .catch((reason) => {
    // reason rejected
    console.log('reason', reason);
  });

- Promise.resolve(value)

  • 作用:
    • 接受一个值,返回一个Promise
  • 特性:
    • 如果value是一个普通值,则将普通值作为新Promise的resolve结果
    • 如果value是一个Promise,则将value原样返回
Promise.resolve(100).then((res) => {
  console.log(res); //100
});

const promise = new Promise((resolve, reject) => {
  reject(200);
});
promise
  .then((res) => {
    console.log(res); //200
  });

总结

至此,Promise的用法就总结完啦,感谢大家的阅读,希望对大家有所帮助。有什么想法快去评论区说出来吧,我们一起探讨,共同进步。
在了解完Promise使用方法之后,下一篇文章,我将通过手写源码的方式,进一步讲解Promise的核心原理。