手写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工作了。

相关推荐
浩男孩7 分钟前
🍀封装个 Button 组件,使用 vitest 来测试一下
前端
蓝银草同学11 分钟前
阿里 Iconfont 项目丢失?手把手教你将已引用的 SVG 图标下载到本地
前端·icon
布列瑟农的星空21 分钟前
重学React —— React事件机制 vs 浏览器事件机制
前端
一小池勺1 小时前
CommonJS
前端·面试
孙牛牛1 小时前
实战分享:一招解决嵌套依赖版本失控问题,以 undici 为例
前端
用户52709648744901 小时前
Git 最佳实践
前端
星秀日1 小时前
JavaWeb--Ajax
前端·javascript·ajax
4_0_41 小时前
全栈视角:从零构建一个现代化的 Todo 应用
前端·node.js
BumBle2 小时前
uniapp 用css实现圆形进度条组件
前端·vue.js·uni-app
杏花春雨江南2 小时前
npm error Could not resolve dependency:
前端·npm·node.js