手动实现Promise

JavaScript是单线程的语言,通过维护执行栈与任务队列而实现了异步操作,setTimeoutAjax就是典型的异步操作,Promise就是异步操作的一个解决方案,用于表示一个异步操作的最终完成或失败, 及其结果值。

语法

new Promise( function(resolve, reject) { /* executor */// 执行代码 需要指明resolve与reject的回调位置
});

executor是带有resolvereject两个参数的函数。Promise构造函数执行时立即调用executor函数,resolvereject两个函数作为参数传递给executorresolvereject函数被调用时,分别将promise的状态改为完成fulfilled或失败rejectedexecutor内部通常会执行一些异步操作,一旦异步操作执行完毕,要么调用resolve函数来将promise状态改成fulfilled,要么调用reject函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise状态为rejectedexecutor函数的返回值被忽略。

状态

Promise本质上就是一个状态机,完整的说是有限状态自动机,给定当前输入与状态,那么输出是可以明确计算的。

pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。

Promise对象只有从pending变为fulfilled和从pending变为rejected的状态改变。只要处于fulfilledrejected,状态就不会再变了。

实现

// 定义_Promise构造函数
function _Promise(fn) {this.status = "pending"; // 定义属性存储状态 // 赋予初始状态pendingthis.value = null; // resolve的valuethis.reason = null; // reject的reasonthis.onFulfilled = []; // 存储then方法中注册的第一个回调函数this.onReject = []; // 存储then方法中注册的第二个回调函数var handler = funct => { // 事件处理函数if(typeof(funct) === "function") { // 如果是函数的话才进行执行if(this.status === "fulfilled") funct(this.value); // 执行并传递valueif(this.status === "rejected") funct(this.reason); // 执行并传递rejected}}// 实现resolve回调var resolve = value => { // 使用箭头函数主要是为了绑定this指向this.status = "fulfilled"; // 设置状态this.value = value; // 得到结果if(value instanceof _Promise){ // 判断返回的值是否为Promise实例value.onFulfilled = this.onFulfilled; // 是则以此链式调用return value;} setTimeout(() => { // 使用setTimeout是为了将回调函数置于任务队列,不阻塞主线程,异步执行,实际promise的回调是置于微队列的,而setTimeout的回调是置于宏队列try {this.onFulfilled.forEach(handler); // 交予事件处理}catch (e){console.error(`Error in promise: ${e}`); // 打印异常reject(e); // reject}}, 0)}// 实现rejectedvar reject = reason => { // 使用箭头函数主要是为了绑定this指向this.status = "rejected"; // 设置状态this.reason = reason; // 得到结果setTimeout(() => { // 置于任务队列try {this.onReject.forEach(handler); // 交予事件处理}catch (e){console.error(`Error in promise: ${e}`); // 打印异常}}, 0)}fn(resolve, reject); // 执行
}// 定义then
// value接收上层结果 --- function处理自身逻辑 --- return传递到下层
_Promise.prototype.then = function(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v; // 转为函数onRejected = typeof onRejected === 'function' ? onRejected : r => r; // 转为函数return new _Promise((resolve, reject) => { // 返回一个新的_Promisethis.onFulfilled.push((value) => { // 将回调函数置于onFulfilledresolve(onFulfilled(value)); // 执行并传递});this.onReject.push((value) => { // 将回调函数置于onRejectreject(onRejected(value)); // 执行并传递});})
}
// 测试
var promise = new _Promise(function(resolve,reject){var rand = Math.random() * 2;setTimeout(function(){if(rand < 1) resolve(rand);else reject(rand);},1000)
})
promise.then((rand) => {console.log("resolve",rand); // resolve回调执行
}, (rand) => {console.log("reject",rand); // reject回调执行
}).then(function(){ // resolve后继续执行return new _Promise(function(resolve,reject){var rand = Math.random() * 2;setTimeout(function(){resolve(rand);},1000)
})
}).then(function(num){ // resolve后继续执行console.log(num,"继续执行并接收参数");return 1;
}).then(function(num){console.log(num,"继续执行并接收参数");
})/*实现的_Promise比较简单实际使用的Promise比较复杂,有各种情况的考虑例子中仅实现了Promise构造函数与then,实际中还有catch、Promise.all、Promise.race、Promise.resolve、Promise.reject等实现*/

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://zhuanlan.zhihu.com/p/47434856
https://www.jianshu.com/p/27735abb91eb
https://segmentfault.com/a/1190000013170460

手动实现Promise 1相关推荐

  1. 手动实现Promise

    基本原理 今天心血来潮,哈哈,就想写个promise对象,需要说的是,我没有参考谁的代码,也没有去看promise的源码,当然,我实现的是一个乞丐版的promise,只有then & catc ...

  2. 手动实现promise基础功能代码并测试自己写的promise库是否符合规范

    promise 解决的问题 回调嵌套/回调地狱 多重异步处理错误捕获不方便 多重异步同步处理的问题 异步并发问题 promise 定义 Promise是一个类 默认浏览器.高版本(ie8以上).nod ...

  3. 定时器和promise_分析 Promise 内部实现

    在介绍Promise之前,首先我们举一个栗子,看下面代码 function success (message) {console.log(message)}function fail (message ...

  4. 有了async/await,你可以丢掉promise链了

    异步函数可能会一直存在,但有些人认为async/await可能会被抛弃. 为什么? 一个常见的误解是async/await和promise是完全不同的东西. 但其实async/await是基于prom ...

  5. 什么是显式promise构造反模式,如何避免呢?

    本文翻译自:What is the explicit promise construction antipattern and how do I avoid it? I was writing cod ...

  6. 常见 Promise 面试问题

    前端面试过程中,基本都会问到 Promise,如果你足够幸运,面试官问的比较浅,仅仅问 Promise 的使用方式,那么恭喜你.事实上,大多数人并没有那么幸运.所以,我们要准备好九浅一深的知识. 常见 ...

  7. util.promisify 的那些事儿

    util.promisify是在node.js 8.x版本中新增的一个工具,用于将老式的Error first callback转换为Promise对象,让老项目改造变得更为轻松. 在官方推出这个工具 ...

  8. 2019 Web 前端热点笔试面试题总结(转载)

    提醒:我只是答案的搬运工,如果在浏览中发现有错误,欢迎评论中提出来,我好修改,谢谢! 简述异步和同步的区别: 同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现 ...

  9. js中Generator函数详解

    文章目录 1. Generator的定义和执行 2. Generator中yield在赋值号左边的情况 3. Generator函数嵌套使用 4. 使用generator函数完成网络请求 1. Gen ...

最新文章

  1. PHP调试的时候遇到Warning: session_start() [function.session-
  2. 肝!2500字 字符串专题总结
  3. Nginx教程-http_core_module变量
  4. linux+平均磁盘请求数量_Linux 查看磁盘IO并找出占用IO读写很高的进程
  5. 【docker】常用docker命令,及一些坑
  6. 三、案例:留言板 url.parse()
  7. asp.net mvc4使用DropDownList
  8. [MAC] 小技巧– 取消屏幕缩放功能,以免不小心误触
  9. 人工智能的未来-揭示人类思维的奥秘How to create a mind - Ray Kurzweil
  10. 给input设置css样式,input能改变css样式吗
  11. 将微信数据提取为exel表格(2022年版)免root 保姆级教程
  12. 第一讲 ISO 17799/27001 标准简介
  13. 快手、携程等公司转战到 ClickHouse,ES 难道不行了?
  14. 微信小程序入门---01
  15. r语言echarts画箱线图_echarter: Echarts的R语言接口
  16. 接口自动化测试(1)
  17. hadoop SWAP交换空间
  18. 局部路径规划算法-DWA动态窗口法
  19. 光谱响应函数概念与等效遥感反射率的计算
  20. flash特效原理:标签云

热门文章

  1. Go单测测试 — 数据库 CRUD 的 Mock 测试
  2. 苹果商店上架流程_苹果TF签名是什么?
  3. Ajax+SpringMVC+JSON登录验证
  4. Spring Bean的一生
  5. Spring核心技术原理-(2)-通过Web开发演进过程了解一下为什么要有Spring AOP?
  6. MySql Cluster 安装,Centos,双管理,多数据,多SQL节点
  7. [转]分布式中Redis实现Session终结篇
  8. swoole_event_add实现异步
  9. Linux第三方软件仓库
  10. centos系统时间不准