(转)手写promise探究底层原理

JavaScript之Promise对象 Promise 对象是一个代理对象(代理一个值),被代理的值在 Promise 对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的 Promise 对象。 Promise 对象有以下两个特点: 对象的状态不受外界影响。Promise 对... 阅读详情
版权声明:转载自 https://blog.youkuaiyun.com/wu_xianqiang/article/details/79596707
ES6新增了promise,看它的用法如下
var promise1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 300);
});

promise1.then(function(value) {
  console.log(value);
  // expected output: "foo"
});

console.log(promise1); 

针对这个例子,我们自己手写一个promise来深入了解下promise的底层原理

function Promise(excutor) {
  let self = this
  self.status = 'pending'
  self.value = null
  self.reason = null
  function resolve(value) {
    if (self.status === 'pending') {
      self.value = value
      self.status = 'fulfilled'
    }
  }
  function reject(reason) {
    if (self.status === 'pending') {
      self.reason = reason
      self.status = 'rejected'
    }
  }
  try {
    excutor(resolve, reject)
  } catch (err) {
    reject(err)
  }
}
 

Promise接收一个函数作为参数,该函数有两个参数,一个是resolve,表示成功时执行的函数,一个是reject,表示失败失败时执行的函数。resolve执行时传入的参数会作为then方法中第一个回调函数的参数,reject执行传入的参数会作为then方法中第二函数回调的参数。

Promise.prototype.then = function (onFulfilled, onRejected) {
  let self = this
  if (self.status === 'fulfilled') {
    onFulfilled(self.value)
  }
  if (self.status === 'rejected') {
    onRejected(self.reason)
  }
}
 

Promise中常常会写一些异步代码,等到异步操作执行完成才会触发resolve或者reject函数,当执行then方法的时候此时的状态还是初始的pending状态,所以为了能取到参数,我们可以通过发布订阅模式来写。

基本调用

function Promise(excutor) {
  let self = this
  self.status = 'pending'
  self.value = null
  self.reason = null
  self.onFulfilledCallbacks = []
  self.onRejectedCallbacks = []
  function resolve(value) {
    if (self.status === 'pending') {
      self.value = value
      self.status = 'fulfilled'
      self.onFulfilledCallbacks.forEach(item => item(self.value))
    }
  }
  function reject(reason) {
    if (self.status === 'pending') {
      self.reason = reason
      self.status = 'rejected'
      self.onRejectedCallbacks.forEach(item => item(self.reason))
    }
  }
  try {
    excutor(resolve, reject)
  } catch (err) {
    reject(err)
  }
}


Promise.prototype.then = function (onFulfilled, onRejected) {
  let self = this
  if (self.status === 'fulfilled') {
    onFulfilled(self.value)
  }
  if (self.status === 'rejected') {
    onRejected(self.reason)
  }
  if (self.status === 'pending') {
    self.onFulfilledCallbacks.push(onFulfilled)
    self.onRejectedCallbacks.push(onRejected)
  }
}
 

我们都知道Promise有一个特点,就是链式调用,当执行then完成后可以继续执行then方法,其实他的原理就是通过返回一个新的Promise实现的,那么then方法中的代码就可以写成下面这样

Promise.prototype.then = function (onFulfilled, onRejected) {
  let self = this
  if (self.status === 'fulfilled') {
    return new Promise((resolve, reject) => {
      onFulfilled(self.value)
    })
  }
  if (self.status === 'rejected') {
    return new Promise((resolve, reject) => {
      onRejected(self.reason)
    })
  }
  if (self.status === 'pending') {
    return new Promise((resolve, reject) => {
      self.onFulfilledCallbacks.push(onFulfilled)
      self.onRejectedCallbacks.push(onRejected)
    })
  }
}
 

then方法接收的两个函数中,可以通过return把值传给下一个步,也可以返回一个新的Promise把值传给下一步,then方法执行的时候有个特点,就是为了保证链式调用,上一次then中不管你是成功还是失败都会把参数作为下一个then中成功时回调的参数,举个例子

let promise1 = new Promise((resolve, reject) => {
  reject('1')
})

let promise2 = promise1.then((res) => {
  return 1
}, (err) => {
  return 2
})
promise2.then((res) => {
  console.log(res)//不管上一次then执行的那个回调函数,在这里都可以接收到参数
})
 

链式调用

Promise.prototype.then = function (onFulfilled, onRejected) {
  let self = this
  if (self.status === 'fulfilled') {
    return new Promise((resolve, reject) => {
      try {
        let x = onFulfilled(self.value)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      } catch (err) {
        reject(err)
      }
    })
  }
  if (self.status === 'rejected') {
    return new Promise((resolve, reject) => {
      try {
        let x = onRejected(self.reason)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      } catch (err) {
        reject(err)
      }
    })
  }
  if (self.status === 'pending') {
    return new Promise((resolve, reject) => {
      self.onFulfilledCallbacks.push(() => {
        let x = onFulfilled(self.value)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      })
      self.onRejectedCallbacks.push(() => {
        let x = onRejected(self.reason)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      })
    })
  }
}
 

注意不管是成功时的回调还是失败时的回调,都有try/catch包裹,不管成功还是失败都会被下一次resolve接收到,只有代码报错才会执行reject,处理特殊情况,then中没有传成功时的回调函数或失败时的回调函数,代码会报错,所以要指定默认值

Promise.prototype.then = function (onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled :  function (data) {return data}
  onRejected = typeof onRejected === 'function' ? onRejected : function (err) {throw err}
  let self = this
  if (self.status === 'fulfilled') {
    return new Promise((resolve, reject) => {
      try {
        let x = onFulfilled(self.value)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      } catch (err) {
        reject(err)
      }
    })
  }
  if (self.status === 'rejected') {
    return new Promise((resolve, reject) => {
      try {
        let x = onRejected(self.reason)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      } catch (err) {
        reject(err)
      }
    })
  }
  if (self.status === 'pending') {
    return new Promise((resolve, reject) => {
      self.onFulfilledCallbacks.push(() => {
        let x = onFulfilled(self.value)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      })
      self.onRejectedCallbacks.push(() => {
        let x = onRejected(self.reason)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      })
    })
  }
}
 

指定默认值得时候注意失败时要继续抛出错误,因为只有代码报错才会走reject函数

catch方法

其实catch方法就是then方法的简写

Promise.prototype.catch = function (fn) {
  return this.then(null, fn)
}
 

完整代码

function Promise(excutor) {
  let self = this
  self.status = 'pending'
  self.value = null
  self.reason = null
  self.onFulfilledCallbacks = []
  self.onRejectedCallbacks = []

  function resolve(value) {
    if (self.status === 'pending') {
      self.value = value
      self.status = 'fulfilled'
      self.onFulfilledCallbacks.forEach(item => item())
    }
  }

  function reject(reason) {
    if (self.status === 'pending') {
      self.reason = reason
      self.status = 'rejected'
      self.onRejectedCallbacks.forEach(item => item())
    }
  }
  try {
    excutor(resolve, reject)
  } catch (err) {
    reject(err)
  }
}


Promise.prototype.then = function (onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled :  function (data) {resolve(data)}
  onRejected = typeof onRejected === 'function' ? onRejected : function (err) {throw err}
  let self = this
  if (self.status === 'fulfilled') {
    return new Promise((resolve, reject) => {
      try {
        let x = onFulfilled(self.value)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      } catch (err) {
        reject(err)
      }
    })
  }
  if (self.status === 'rejected') {
    return new Promise((resolve, reject) => {
      try {
        let x = onRejected(self.reason)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      } catch (err) {
        reject(err)
      }
    })
  }
  if (self.status === 'pending') {
    return new Promise((resolve, reject) => {
      self.onFulfilledCallbacks.push(() => {
        let x = onFulfilled(self.value)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      })
      self.onRejectedCallbacks.push(() => {
        let x = onRejected(self.reason)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      })
    })
  }
}

Promise.prototype.catch = function (fn) {
  return this.then(null, fn)
}
 

Github查看源码

Promise对象详解(涉及回调地狱的解决、async&await的使用) 文章目录一、Promise对象2.1、Promise简介2.2、Promise产生背景2.3、Promise的基本使用2.4、使用Promise解决回调地狱2.4.1、如何解决多重请求(回调地狱)2.4.2、简化多重请求的promise写法2.5、Promise的方法使用2.6、异步代码同步化 之前发现自己对async&await的理解没有那么深,所以翻出笔记又看了一遍! 一、Promise对象 2.1、Promise简介 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事 阅读详情

相关推荐

promise解析

Promise 是 JavaScript 中用于异步编程的一个重要概念。它表示一个尚未完成但预期将来会完成的操作的结果。使用 Promise 可以优雅地处理异步操作及其结果,避免回调地狱(callback hell)的出现。下面我将从基本概念、创建和使用 Promise、以及常见的方法等方面进行解析。

xyfwang的博客 1233

Promise对象

Promise是异步编程的一种解决方案 Promise,就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果;从语法上说,Promise是一个对象,从它可以获取异步操作的消息;Promise提供统一的API,各种异步操作都可以用同样的方法进行处理 Promise对象有以下2个特点: 1.对象的状态不受外界影响;Promise对象代表一个异步操作,有三种状态:pending(进行中)、fufilled(已成功)、rejected(已失败);只有异步操作的结果,可以决定当前是哪一种状

amuist_ting的博客 4762

手写Promise 理解promise底层原理

本文参考了此博客,在网上浏览了很多关于Promise的相关资料,promise可以说是JavaScript的重难点了,其中,很是感谢阮一峰老师的博客讲解以及MDN上的文档教程 如对Promise不太熟悉的同学,可以先浏览Promise工作原理分析,如有不同意见,欢迎讨论,一起进步。 Promise基本流程 function doSomething(){ var p1 = new Promise(function (resolve, reject) { setTimeout(()=.

Niall_Tonshall的博客 2721

Promise对象(超详细)

Promise是异步编程的一种解决方案,比回调函数和事件更合理且更强大。可以理解为一个容器,里面保存着某个未来才会结束的事件的结果

qq_51904231的博客 2398

手写实现promise以及promise.all和promise.race

之前写的一个promise太多了,面试写下来的话。。。。emmm,所以在复习时又写一个简单的。 promise class Promsie { constructor(fn) { //三个状态 this.status = 'pending', this.resolve = undefined; this.reject = undefined; let resolve = value => {

qq_40619263的博客 3651

手写promise的原理及思路

highlight: a11y-dark theme: healer-readable 手写promise思路 先逐步分析,一步一步的写代码,最终有完整示例 1.promise是一个类,参数是一个函数执行器,且会立即执行。函数执行器接受两个参数,一个成功回调resolve,一个失败回调reject class MyPromise { constructor(executor) { executor(this.resolve.bind(this), this.reject.bind(.

qq_35258995的博客 1805

【JavaScript】手写Promise

面试中经常会被问到你会手写Promise吗?本文带你手撸Promsie

编码世界 5489

前端核心进阶:从原理到手写Promise、防抖节流与深拷贝

本文深入解析JavaScript三大核心功能实现:1)手写Promise完整实现,包括状态管理、异步处理、链式调用和返回值处理;2)防抖函数实现,支持立即执行和延迟执行模式,通过定时器控制高频事件;3)节流函数实现,采用时间戳和定时器双保险策略优化性能。通过代码实现揭示异步编程、性能优化等底层原理,帮助开发者掌握核心概念。

欢迎来到我的技术博客——一个用代码编织思想的数字花园 🌱 855

【一篇文章讲透promise底层原理并手写promise】

微任务模拟:用 queueMicrotask 模拟原生 Promise 的微任务(原生 then 回调是微任务,优先于宏任务执行)。1.异步操作需要用回调函数接收结果,当多个异步操作嵌套依赖时,代码会层层缩进,像金字塔一样扭曲,可读性、可维护性极差,这就是。回调队列:异步 Promise(定时器 / 接口)会把then回调存入队列,状态变更后批量执行。我们回到promise的作用来解答这个问题,因为异步执行的结果必须要保证,即。我们来讲一下promise解决的另一个问题,异步结果值时效不可控的问题。

weixin_43863367的博客 536

前端面试大全:手写 Promise

(内容同步自小邹的头条号:沪漂程序员的生活史) 在上一篇文章中我们了解了 Promise 的一些易错点,那这一篇文章,我们会通过手写一个符合 Promise/A+ 规范的 Promise 来深入理解它,并且手写 Promise 也是一道大厂常考题,在进入正题之前,推荐各位去网上找下Promise/A+规范,这样才能更好地理解这个章节的代码。   实现一个简易版 Promise 在完成符...

itKingOne的博客 2725

向量库深度解析:选型、索引原理与生产实践

本文系统解析五大主流向量库(pgvector、Milvus、Weaviate、ChromaDB、Faiss)的定位、优缺点与适用场景,深入拆解FLAT、IVF、HNSW等核心索引原理,并重点分析Milvus的Compaction机制。针对数据治理场景,提供精准选型建议:中小规模优先pgvector或Weaviate,超大规模选择Milvus,开发测试推荐ChromaDB。核心索引推荐HNSW,兼顾检索速度与召回率。全文从理论到实践,为开发者提供清晰的向量库选型逻辑与生产落地指南。

a123147abc的博客 360

ES6 - 从Promise入门到深入原理(手写一个自己的Promise)

事件和回调函数的缺陷 我们习惯于使用传统的回调或者事件处理来解决异步问题 事件: 某个对象的属性是一个函数, 当发生一件事时, 运行该函数 dom.onclick = function() { // ...执行的代码 } 回调:运行某个函数以实现某个功能的时候, 传入一个函数作为参数, 当某个特定的条件下的时候, 就会触发该函数 dom.addEventListner('click', ...

前端攻城狮Dannis 5268

机器人运动不流畅?手把手教你用ACCSET调整ABB/FANUC点位加速度

本文针对ABB和FANUC工业机器人运动不流畅、拐角抖动、到位震颤等常见问题,提供了详细的解决方案。核心在于使用ACCSET指令(ABB)或ACC选项(FANUC)调整机器人的点位加速度与减速度参数。文章通过实战案例与系统化调试流程,手把手指导工程师优化运动性能,实现平稳、精准的机器人运动控制。

gpu4optimizer的博客 284

javascirpt手写promise原理由浅入深

javascript手写promise原理,提高js功底,有助于面试,有助于读懂大佬源码

weixin_44600810的博客 694

从2804云台电机到桌面机械臂:一个STM32/GD32玩家的FOC驱动踩坑全记录

本文详细记录了从2804云台电机到桌面机械臂的FOC驱动开发历程,涵盖了硬件选型、驱动方案优化、软件调试等关键环节。特别分享了L6234P驱动芯片的发热问题、AS5600编码器的I2C通信陷阱以及PID调参的实战经验,为DIY爱好者提供了宝贵的参考。

weixin_26897585的博客 477

开放自己本机的mysql允许别人连接

需要在左下角搜索记事本应用,右键以管理员身份运行,之后按照上述地址找到my.ini文件,ctrl+F搜索到[mysqld],修改或添加 bind-address 设置,将其更改为 0.0.0.0 或你的计算机的 IP 地址。打开 MySQL 的配置文件 my.ini。username和密码是第3步创建能从远程地址访问的用户和密码,ip地址是ipconfig查看的地址(前提是能ping通,才能连接该地址对应的数据库)。使用 MySQL 命令行连接到自己的数据库,并创建一个能够从远程地址访问的用户。

m0_74824687的博客 1167

手写简易Promise,吃透异步底层核心原理

本文介绍了手写简易Promise的核心实现过程,帮助开发者深入理解JS异步机制。文章首先指出大多数开发者只懂使用Promise而不懂原理的问题,强调手写Promise是理解异步编程的关键。然后分步骤实现了一个极简版Promise:1)搭建基础结构实现状态管理;2)完善then方法处理同步场景;3)通过回调函数缓存解决异步问题;4)实现链式调用。文章重点解析了Promise三大核心特性(状态不可逆、异步回调缓存、链式调用),并指出手写Promise对理解EventLoop、微任务等异步概念的重要意义。虽然未完

2609_96580141的博客 498

【IoT】 产品设计之结构设计:如何设计产品按键

1、硅胶按键功能实现有两种接触方式 1)硅胶按键按压在DOME片(锅仔片)上 通常用在手机、儿童手表手机、防水手机等防水设备上。 2)硅胶按键增加导电基,一种黑色的导电碳粒,实现回路导电 通常用在遥控器、电脑键盘、特殊设备上。 两种方式结构设计原理是一样的,按键的固定与配合间隙与行程要确保好。 2、硅胶遥控器按键的结构方式(导电基) 按键帽为大颗粒实心的,触点为黑色导电基,通过压注成型融合为一体,那么这种按键结构设计时需要注意那些呢? 最主要的是按键按压回弹的手感,由于没有DOME片实现

产品线负责人 8666

我终于搞懂了Promise,并且手写了一遍。

摘要:文章深入解析了Promise如何解决回调地狱问题。Promise通过将异步返回值存储起来,使用.then()实现链式调用,避免了多层嵌套回调。其核心机制是利用JS的微任务队列,确保resolve存值后立即执行.then()回调。手写Promise的实现思路包括:定义类管理状态和结果、实现resolve/reject方法、处理异步回调缓存、支持链式调用等。关键在于理解Promise本质是将异步操作同步化,通过状态管理和任务队列协调执行顺序。

A6516565189的博客 1293

RK3588开发笔记-MIPI-CSI接口视频解码芯片XS9922B调试

Rockchip RK3588 是一款高性能的处理器,支持多种摄像头接口,包括 MIPI(Mobile Industry Processor Interface)接口。MIPI是一种用于移动设备和嵌入式系统中的摄像头、显示器和其他传感器设备的串行接口标准。MIPI是MIPI联盟发起的为移动应用处理器制定的开放标准。CSI-2(Camera Serial Interface 2)是MIPI 联盟定义的另一种高速接口,主要用于摄像模组和处理器之间的连接。

flypig has a dream! 6860

OSG三维渲染引擎编程学习之一:“第一章:OSG介绍” 之 “1.1 OSG简介”

第一章:OSG介绍; 1.1 OSG简介。

LuckyHanMo的博客 3222

从回调地狱到手写 Promise:一次彻底搞懂 JavaScript 异步的底层逻辑

本文介绍了JavaScript中Promise的核心概念和使用方法。首先通过餐厅点餐场景生动解释了Promise的工作原理,包括pending、fulfilled和rejected三种状态。重点讲解了then链式调用的实现机制,catch和finally的本质,以及async/await作为Promise语法糖的作用。文章还提供了一个简化版Promise的手写实现,并介绍了Promise.all和Promise.race等静态方法。

qi_bai_jin的博客 1560

Wsl/InstallDistro/Service/RegisterDistro/CreateVm/HCS/E_INVALIDARG

摘要:安装WSL2时遇到E_INVALIDARG错误(多核CPU问题),可通过创建.wslconfig配置文件解决。配置内容包括:渐进式内存回收、自动代理、模拟虚拟系统调用、限制内存为4GB和处理器核心数为4。需确保已启用虚拟机平台和Linux子系统功能。 (98字)

猿小白的博客 1047

Promise原理及手写Promise

一、Promise原理: Promise 原理围绕以下三个问题进行解决: (有任何一步不了解的话请先往下看手写Promise,会一步步剖析原理,看完后再继续回顾这里!!) 1. 怎么实现异步? Promise内部then函数注册后续需要执行的函数,resolve函数执行。需要保证函数在执行前都已注册好, 解決:resolve内部执行函数的代码需要加入延时机制setTimeout...

huangzhin的博客 804

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【手写Promise】史上最最最详细的手写Promise教程

转载自https://yq.aliyun.com/articles/613412 class Promise{ constructor(executor){ this.state = 'pending'; this.value = undefined; this.reason = undefined; this.onResolvedCallbacks = []; this.onRejectedCallbacks = []; let resolve = va

Anles的博客 3769

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

前端面试必考 手写promise.all() 手写promise.race() 手写promise

复习到了Promise的知识点 不得不手写这里重要的代码 //实现promise.all() /* Promise函数对象的all方法 返回一个promise对象,只有当所有promise都成功时返回的promise状态才成功 */ Promise.myAll = function(promises){ const values = new Array(promises.length) var resolvedCount = 0; //计状态为resolved的promise的数量 r

weixin_43939659的博客 2603

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

上一篇: webstorm配置ftp并上传到服务器
下一篇: vue项目打包成dist后,如何部署到本地呢
tomotoCoder
博客等级 码龄9年 8粉丝 12原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值