手写Promise-什么是Promise

在学习JS的异步编程时,你总是绕不Promise。在开发时总是会接触它,用时觉得也没有什么,用的时候感觉也就那样,但是到了面试时的时候,一道道要你说出执行顺序的时候又犯了难。不知道你是不是跟我一样有这样的感受。本系列将以手写Promise的方式来了解Promise,在手写Promise的同时体验到各种开发技巧。提高一下自身的开发思维。

那我们开始手写Promise的旅程吧!

什么是Promise

Promise是什么呢?可以想象现实生活中的一个小场景:淘宝购物

  1. 当你看到了心仪的商品时,你点击购买然后付钱后,此处于发货和配送中。
  2. 当心仪商品配送到家后,最终会产生两种结果:
    • 成功:实物和淘宝看到的一样非常满意。交易成功!
    • 失败:实物和淘宝看到的相差甚远不是很满意。退货!

我们再来看看Promise是怎样的呢?

  • Promise是一个对象,代表了一个异步操作最终完成的以及返回的结果。
  • Promise操作时有三种状态:
    • pending:初始状态,表示正在处理中。
    • fulfilled:操作成功完成
    • rejected:操作失败
  • Promise的状态一旦发生改变,不能更改。这是Promise的关键特性。

为什么需要Promise

在没有Promise的时候,是怎样编写异步代码的呢?主要是回调函数。可以想象下网络请求调用后台接口时,一个接口依赖一个接口再依赖另一个接口的场景。通过回调函数如何编写呢?

js 复制代码
/* jquery回调函数的书写方式 */
$.ajax({
  url: "/api/userInfo",
  type: "GET",
  dataType: "json",
  success: function (info) {
    $.ajax({
      url: "/api/roleInfo",
      data: { userId: info.id },
      success: function (role) {
        $.ajax({
          url: "api/menuInfo",
          data: { roleId: role.id },
          success: function () {
            /* 还有可能需要调用其他接口*/
          },
        });
      },
    });
  },
});

上述代码发现回调函数层层嵌套。形成了'金字塔'的形状。代码之间耦合度非常高,维护代码极其困难,一旦有错误处理起来比较困难。就像开发人员天天骂是一坨屎的代码。😂

Promise的出现便是为了解决这样的问题而诞生的。它通过.then.catch方法实现了链式调用。将异步的流程阅读性强,接近于同步线性流程。将上述代码改为promise的方式。

js 复制代码
/* jquery支持Promise的书写方式 */
$.ajax({
  url: "/api/userInfo",
  type: "GET",
  dataType: "json",
})
  .then((info) => $.ajax({ url: "/api/roleInfo", data: { userId: info.id } }))
  .then((role) => $.ajax({ url: "/api/menuInfo", data: { roleId: role.id } }))
  .then(function (menu) { /* 还可以继续处理 */ })
  .fail((error) => {  /* 处理错误 */ });

修改后的代码从上往下的线性结构,在阅读代码和可维护性上都大大提升。错误处理上更加方便。

基本用法

知道promise为什么出现后,也知道了它的好处,那我们要如何使用它呢?首先要知道Promise是一个构造函数(new Promise(executor))。接收一个参数executor函数。此函数会立刻执行,它接收两个参数(也是函数):

  • resolve: 当异步操作成功时调用,将状态pending改为fulfilled
  • reject: 当异步操作失败时调用,将状态pending改为rejected
js 复制代码
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if(success) {
        resolve('操作成功');
        // reject('失败了'); // 此处不会执行 状态改为了fulfilled 不能再改为
    } else {
        reject('拒绝此操作');
        // resolve('成功啦'); // 此处不会执行 状态改为了rejected 不能再改为
    }
  }, 1000)
})

Promise通过.then().catch().finally()来接收成功和失败结果。

  • .then(onFulfilled, onRejected):接收两个回调函数,分别处理成功和失败。然后返回一个新的Promise,这便是可以链式调用的原因。
  • .catch(onRejected) :专门处理失败的,其实就是.then(null, onRejected)的语法糖。
  • .finally(onFinally):无论成功或失败都会执行,一般用于清理工作。
js 复制代码
const p = new Promise((resolve, reject) => {
  resolve("lucy");
})
  .then((name) => {
    console.log(`接收到了面试人:${name}`); // 此处会执行
  })
  .catch((error) => {
    console.log(error);
  })
  .finally(() => {
    console.log("finally"); // 不管成功失败,都会执行
  });

小结

本文讲述内容如下:

  • 什么是Promise,它是一个构造函数,接收一个函数,初始化立即执行,此函数分别接收处理成功和失败的函数。
  • Promise本质是一个状态机,包括三种状态: pendingfulfilledrejected。状态一旦改变则不可逆
  • then方法主要注册回调函数到对应状态上,并返回一个新的Promise以支持链式调用
  • catch方法专门处理失败,finally方法是不管成功失败都会执行。
  • Promise底层里的then/catch不是立即执行的,它是放入了微任务队列中,等待渲染主线程检测到后执行的。

了解Promise之后,接下来进行手写Promise工作了。

相关推荐
拜无忧1 小时前
html,svg,花海扩散效果
前端·css·svg
DevUI团队1 小时前
🚀 MateChat V1.8.0 震撼发布!对话卡片可视化升级,对话体验全面进化~
前端·vue.js·人工智能
RoyLin1 小时前
TypeScript设计模式:责任链模式
前端·后端·typescript
一枚前端小能手1 小时前
📋 前端复制那点事 - 5个实用技巧让你的复制功能更完美
前端·javascript
三小河1 小时前
解决vite环境下调用获取二进制文件流 部分文件报错 (failed)net::ERR_INVALID_HTTP_RESPONSE)
前端
好好好明天会更好1 小时前
pinia从定义到运用
前端·vue.js
代码小学僧1 小时前
Vite 项目最简单方法解决部署后 Failed to fetch dynamically imported Error问题
前端·vue.js·vite
RoyLin1 小时前
TypeScript设计模式:装饰器模式
前端·后端·typescript
掘金一周2 小时前
Flutter Riverpod 3.0 发布,大规模重构下的全新状态管理框架 | 掘金一周 9.18
前端·人工智能·后端