您当前的位置:首页 > 电脑百科 > 程序开发 > 前端

两年前端经验还不会手写Promise?

时间:2024-03-07 13:50:58  来源:微信公众号  作者:海燕技术栈

什么是promise?

当我们处理异步操作时,我们经常需要进行一系列的操作,如请求数据、处理数据、渲染UI等。在过去,这些操作通常通过回调函数来处理,但是回调函数嵌套过多会导致代码难以维护,产生回调地狱(Callback Hell)。Promise就是一种用于解决异步编程问题的解决方案。

概念?

Promise是一种代表异步操作最终完成或失败的对象。它是ES6中新增的语法特性,通过Promise对象,可以更加优雅地处理异步操作。Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。一旦Promise的状态发生改变,就不会再变。

Promise的作用:

  1. 异步操作的管理: Promise提供了一种标准的方式来管理异步操作,使得代码更加清晰易读。
  2. 解决回调地狱问题: Promise的链式调用(ChAIning)可以避免多层嵌套的回调函数,使代码结构更加清晰。
  3. 错误处理: Promise提供了统一的错误处理机制,通过catch方法可以捕获Promise链中的错误,避免了未捕获的异常。
  4. 并行和串行执行: Promise可以串行或并行执行多个异步操作,并通过Promise.all和Promise.race等方法来管理多个Promise实例的状态。

Promise的方法:

  1. then(onFulfilled, onRejected): then方法用于注册Promise的成功和失败回调,并返回一个新的Promise,可以实现链式调用。
  2. catch(onRejected): catch方法用于捕获Promise链中的错误,并返回一个新的Promise,用于处理错误。
  3. finally(onFinally): finally方法用于注册一个回调函数,无论Promise的状态如何都会被调用。
  4. Promise.resolve(value): Promise.resolve方法用于将一个值包装成Promise对象,如果参数是Promise实例,则直接返回该实例。
  5. Promise.reject(reason): Promise.reject方法用于返回一个状态为rejected的Promise对象,并将指定的原因传递给Promise的回调函数。
  6. Promise.all(iterable): Promise.all方法用于将多个Promise实例包装成一个新的Promise实例,当所有Promise实例的状态都变为fulfilled时,新的Promise的状态才变为fulfilled;当其中一个Promise实例的状态变为rejected时,新的Promise的状态就变为rejected。
  7. Promise.race(iterable): Promise.race方法用于将多个Promise实例包装成一个新的Promise实例,当其中一个Promise实例的状态发生改变时,新的Promise的状态就跟着改变。
  8. Promise.allSettled(iterable): Promise.allSettled方法用于将多个Promise实例包装成一个新的Promise实例,无论这些Promise的状态如何,最终返回的Promise实例的状态都会变为fulfilled,返回的结果是一个包含所有Promise的状态和结果的数组。

实现Promise的重点

如果要手写Promise,那就需要先理清楚重点,然后实现主,要集中在以下几个方面:

  1. 状态管理: Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。在Promise的生命周期中,它会从pending状态转变为fulfilled或rejected状态,一旦状态改变就不可再变。状态的变化由Promise的执行器函数中的resolve和reject函数触发。
  2. 链式调用: Promise允许通过then方法链式调用,每次调用then都会返回一个新的Promise实例,以实现更加灵活的异步操作。通过链式调用,可以串联多个异步操作,并在每个操作完成后执行特定的处理逻辑。
  3. 错误处理: Promise提供了catch方法用于捕获Promise链中的错误。在Promise链中,如果某个Promise发生了rejected状态,它会沿着链路向下传递,直到被catch方法捕获到错误,或者如果没有捕获到错误,则会导致未捕获的异常。
  4. 异步执行: Promise的then方法中的回调函数会在当前执行栈执行完成后,通过事件循环机制被放入下一个事件循环中执行,这样可以保证回调函数总是在当前代码执行完成后执行,从而实现异步操作。
  5. 解决回调地狱问题: Promise的链式调用可以解决回调地狱(Callback Hell)的问题,使得代码更加清晰易读。通过Promise,可以更加优雅地处理多个异步操作的串行或并行执行,避免了深度嵌套的回调函数。

实现Promise

在知道Promise的概念以及重点之后,我们来简单实现一下:

class MyPromise {
  constructor(executor) {
    // 初始化Promise的状态为pending
    this.state = 'pending';
    // 存储Promise的成功值
    this.value = undefined;
    // 存储Promise的失败原因
    this.reason = undefined;
    // 存储成功状态下的回调函数数组
    this.onResolvedCallbacks = [];
    // 存储失败状态下的回调函数数组
    this.onRejectedCallbacks = [];


    // 定义resolve函数,用于将Promise状态从pending改变为fulfilled
    const resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        // 执行成功状态下的回调函数数组中的每个回调函数
        this.onResolvedCallbacks.forEach(callback => callback());
      }
    };


    // 定义reject函数,用于将Promise状态从pending改变为rejected
    const reject = reason => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        // 执行失败状态下的回调函数数组中的每个回调函数
        this.onRejectedCallbacks.forEach(callback => callback());
      }
    };


    try {
      // 执行executor函数,并将resolve和reject函数作为参数传递给executor
      executor(resolve, reject);
    } catch (error) {
      // 如果executor执行过程中发生了错误,则将Promise状态改变为rejected
      reject(error);
    }
  }


  // then方法用于注册Promise的成功和失败回调,并返回一个新的Promise
  then(onFulfilled, onRejected) {
    // 创建一个新的Promise实例
    const newPromise = new MyPromise((resolve, reject) => {
      // 当前Promise的状态为fulfilled时
      if (this.state === 'fulfilled') {
        // 异步执行onFulfilled回调函数,并处理返回值result
        setTimeout(() => {
          try {
            const result = onFulfilled(this.value);
            // 将返回值result传递给resolvePromise函数,处理新Promise的状态
            resolvePromise(newPromise, result, resolve, reject);
          } catch (error) {
            // 如果执行onFulfilled回调函数过程中发生了错误,则将新Promise的状态改为rejected
            reject(error);
          }
        }, 0);
      }


      // 当前Promise的状态为rejected时
      if (this.state === 'rejected') {
        // 异步执行onRejected回调函数,并处理返回值result
        setTimeout(() => {
          try {
            const result = onRejected(this.reason);
            // 将返回值result传递给resolvePromise函数,处理新Promise的状态
            resolvePromise(newPromise, result, resolve, reject);
          } catch (error) {
            // 如果执行onRejected回调函数过程中发生了错误,则将新Promise的状态改为rejected
            reject(error);
          }
        }, 0);
      }


      // 当前Promise的状态为pending时
      if (this.state === 'pending') {
        // 将成功和失败回调函数分别添加到对应的回调函数数组中
        this.onResolvedCallbacks.push(() => {
          // 异步执行成功回调函数,并处理返回值result
          setTimeout(() => {
            try {
              const result = onFulfilled(this.value);
              // 将返回值result传递给resolvePromise函数,处理新Promise的状态
              resolvePromise(newPromise, result, resolve, reject);
            } catch (error) {
              // 如果执行成功回调函数过程中发生了错误,则将新Promise的状态改为rejected
              reject(error);
            }
          }, 0);
        });


        this.onRejectedCallbacks.push(() => {
          // 异步执行失败回调函数,并处理返回值result
          setTimeout(() => {
            try {
              const result = onRejected(this.reason);
              // 将返回值result传递给resolvePromise函数,处理新Promise的状态
              resolvePromise(newPromise, result, resolve, reject);
            } catch (error) {
              // 如果执行失败回调函数过程中发生了错误,则将新Promise的状态改为rejected
              reject(error);
            }
          }, 0);
        });
      }
    });


    // 返回新的Promise实例
    return newPromise;
  }
}


// resolvePromise函数用于处理then方法中回调函数返回的结果
function resolvePromise(newPromise, result, resolve, reject) {
  // 如果新的Promise和返回值是同一个对象,则抛出错误
  if (newPromise === result) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }


  // 如果返回值是Promise实例,则等待该Promise的状态改变,并根据其状态决定新Promise的状态
  if (result instanceof MyPromise) {
    result.then(resolve, reject);
  } else {
    // 如果返回值不是Promise实例,则将返回值传递给resolve函数,将新Promise的状态改变为fulfilled
    resolve(result);
  }
}

这段代码实现了一个非常基础的Promise,主要有以下几个部分:

  1. 构造函数:

构造函数接受一个执行器函数作为参数,在构造函数内部定义了resolve和reject函数,并执行了执行器函数。执行器函数接受两个参数,分别是resolve和reject,它们分别用于将Promise状态从pending改变为fulfilled和rejected。

执行器函数中通过try...catch块捕获可能的异常,并在捕获到异常时将Promise状态改变为rejected。

  1. then方法:

then方法用于注册Promise的成功和失败回调,并返回一个新的Promise。它接受两个参数,分别是成功回调onFulfilled和失败回调onRejected。

在then方法内部,根据当前Promise的状态(pending、fulfilled、rejected),分别处理执行成功和执行失败的逻辑,并在异步环境下使用setTimeout确保执行顺序。

如果then方法中的回调函数返回了一个Promise,则等待该Promise的状态改变,并根据其状态决定新的Promise的状态。

  1.  

    resolvePromise函数:

     

resolvePromise函数用于处理then方法中回调函数返回的结果。如果结果是一个Promise,则等待该Promise的状态改变,并根据其状态决定新的Promise的状态。



Tags:Promise   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
两年前端经验还不会手写Promise?
什么是promise?当我们处理异步操作时,我们经常需要进行一系列的操作,如请求数据、处理数据、渲染UI等。在过去,这些操作通常通过回调函数来处理,但是回调函数嵌套过多会导致代码...【详细内容】
2024-03-07  Search: Promise  点击:(23)  评论:(0)  加入收藏
JavaScript 和 Typescript 中的 Promise
厌倦了理清 JavaScript 或 TypeScript 项目中的异步代码?您是否希望有一种方法可以使您的异步进程像运转良好的机器一样运行? 如果是这种情况,我们为您提供了一个解决方案:promi...【详细内容】
2023-01-09  Search: Promise  点击:(291)  评论:(0)  加入收藏
如何优雅地中断 Promise?
大家在平时的开发过程中估计不会经常碰到需要主动取消一个 Fetch 请求的需求,所以一部分同学可能对这一块知识不是很了解。没有关系,看完这篇文章你就能够掌握关于如何终止一...【详细内容】
2022-12-25  Search: Promise  点击:(160)  评论:(0)  加入收藏
MVVM与MVC对比、Promise 对象
MVVM 的定义 M (Model): 数据来源,主要指从后端获取的数据 V (View): 界面,页面。主要由 HTML 和 CSS 来构建 VM (ViewModel): 数据与视图关联起来,数据和 DOM 已经建立了关联,...【详细内容】
2022-10-24  Search: Promise  点击:(267)  评论:(0)  加入收藏
深入理解JavaScript的事件循环、callback、promise和async/await
现在Web应用程序对网页的动态交换需要越来越高,因此越来越有必要进行密集的操作,例如发出外部网络请求以检索API数据。要在 JavaScript 中处理这些操作,开发人员必须使用异步...【详细内容】
2022-10-11  Search: Promise  点击:(331)  评论:(0)  加入收藏
20分钟带你掌握JS Promise和Async/Await
一般在开发中,查询网络 API 操作时往往是比较耗时的,这意味着可能需要一段时间的等待才能获得响应。因此,为了避免程序在请求时无响应的情况,异步编程就成为了开发人员的一项基...【详细内容】
2021-03-31  Search: Promise  点击:(514)  评论:(0)  加入收藏
初学者应该看的JavaScript Promise 完整指南
这篇文章算是 JavaScript Promises 比较全面的教程,该文介绍了必要的方法,例如 then,catch和finally。此外,还包括处理更复杂的情况,例如与Promise.all并行执行Promise,通过Promis...【详细内容】
2020-09-09  Search: Promise  点击:(293)  评论:(0)  加入收藏
JavaScript 中对于Promise的理解
Promise 是 CommonJS 中的规范,它能够帮助我们控制代码流程,避免函数的多层嵌套。现在 Web 前端异步编程越来越普遍,它的出现让异步编程变得更佳的容易理解。由于它越来越受到...【详细内容】
2019-11-11  Search: Promise  点击:(632)  评论:(0)  加入收藏
Promise 的相关概念 与API 详情解释
Promise: 许诺用来创建promise对象的构造函数: function Promise (excutor) {}简洁描述: 一个promise对象用来表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值...【详细内容】
2019-10-14  Search: Promise  点击:(640)  评论:(0)  加入收藏
Javascript:Promise对象基础
兼容性promise兼容性一、Promise 的状态Promise有3种状态: Pending:进行中 Resolved(Fulfilled):已完成 Rejected:已失败Promise状态的改变只有两种: Pending --> Resolved Pendi...【详细内容】
2019-08-02  Search: Promise  点击:(1049)  评论:(0)  加入收藏
▌简易百科推荐
20k级别前端是怎么使用LocalStorage的,想知道吗?
当咱们把咱们想缓存的东西,存在localStorage、sessionStorage中,在开发过程中,确实有利于咱们的开发,咱们想看的时候也是一目了然,点击Application就可以看到。前言大家好,我是林...【详细内容】
2024-03-26  前端之神  微信公众号  Tags:前端   点击:(10)  评论:(0)  加入收藏
前端不存在了?盲测64%的人更喜欢GPT-4V的设计,杨笛一等团队新作
3 月 9 日央视的一档节目上,百度创始人、董事长兼 CEO 李彦宏指出,以后不会存在「程序员」这种职业了,因为只要会说话,人人都会具备程序员的能力。「未来的编程语言只会剩下两种...【详细内容】
2024-03-11  机器之心Pro    Tags:前端   点击:(9)  评论:(0)  加入收藏
前端开始“锈化”?Vue团队开源JS打包工具:基于Rust、速度极快、尤雨溪主导
Vue 团队已正式开源Rolldown —— 基于 Rust 的 JavaScrip 打包工具。Rolldown 是使用 Rust 开发的 Rollup 替代品,它提供与 Rollup 兼容的应用程序接口和插件接口...【详细内容】
2024-03-09  OSC开源社区    Tags:Vue   点击:(11)  评论:(0)  加入收藏
两年前端经验还不会手写Promise?
什么是promise?当我们处理异步操作时,我们经常需要进行一系列的操作,如请求数据、处理数据、渲染UI等。在过去,这些操作通常通过回调函数来处理,但是回调函数嵌套过多会导致代码...【详细内容】
2024-03-07  海燕技术栈  微信公众号  Tags:Promise   点击:(23)  评论:(0)  加入收藏
网站开发中的前端和后端开发有什么区别
前端开发和后端开发都是干什么的?有哪些区别?通俗地讲,前端干的工作是用户可以直接看得见的,而后端开发的工作主要在服务端,用户不太能直接看到。虽然前端开发和后端开发的工作有...【详细内容】
2024-02-21  CarryData    Tags:前端   点击:(31)  评论:(0)  加入收藏
网站程序开发中的前后端分离技术
随着互联网的快速发展和技术的不断创新,传统的网站开发模式已经难以满足日益增长的业务需求。为了提高开发效率、增强系统的可维护性和可扩展性,前后端分离技术逐渐成为了网站...【详细内容】
2024-01-31  网站建设派迪星航    Tags:前后端分离   点击:(23)  评论:(0)  加入收藏
如何优雅的实现前端国际化?
JavaScript 中每个常见问题都有许多成熟的解决方案。当然,国际化 (i18n) 也不例外,有很多成熟的 JavaScript i18n 库可供选择,下面就来分享一些热门的前端国际化库!i18nexti18ne...【详细内容】
2024-01-17  前端充电宝  微信公众号  Tags:前端   点击:(67)  评论:(0)  加入收藏
Vue中Scope是怎么做样式隔离的?
scope样式隔离在 Vue 中,样式隔离是通过 scoped 特性实现的。当在一个组件的 <style> 标签上添加 scoped 特性时,Vue 会自动为这个样式块中的所有选择器添加一个唯一的属性,以...【详细内容】
2024-01-04  海燕技术栈  微信公众号  Tags:Vue   点击:(80)  评论:(0)  加入收藏
vue3中 ref和 reactive的区别 ?
最近有朋友在面试过程中经常被问到这么一个问题,vue3 中的ref 和 reactive的区别在哪里,为什么 要定义两个API 一个 api不能实现 响应式更新吗??带着这个疑问 ,我们 接下来进行逐...【详细内容】
2024-01-03  互联网高级架构师  今日头条  Tags:vue3   点击:(36)  评论:(0)  加入收藏
React18 与 Vue3 全方面对比
1. 编程风格 & 视图风格1.1 编程风格 React 语法少、难度大;Vue 语法多,难度小例如指令:Vue<input v-model="username"/><ul> <li v-for="(item,index) in list" :key="inde...【详细内容】
2024-01-03  爱做梦的程序员  今日头条  Tags:Vue3   点击:(72)  评论:(0)  加入收藏
站内最新
站内热门
站内头条