手动实现Promise 1
手动实现Promise
JavaScript
是单线程的语言,通过维护执行栈与任务队列而实现了异步操作,setTimeout
与Ajax
就是典型的异步操作,Promise
就是异步操作的一个解决方案,用于表示一个异步操作的最终完成或失败, 及其结果值。
语法
new Promise( function(resolve, reject) { /* executor */// 执行代码 需要指明resolve与reject的回调位置
});
executor
是带有resolve
和reject
两个参数的函数。Promise
构造函数执行时立即调用executor
函数,resolve
和reject
两个函数作为参数传递给executor
。resolve
和reject
函数被调用时,分别将promise
的状态改为完成fulfilled
或失败rejected
。executor
内部通常会执行一些异步操作,一旦异步操作执行完毕,要么调用resolve
函数来将promise
状态改成fulfilled
,要么调用reject
函数将promise
的状态改为rejected
。如果在executor
函数中抛出一个错误,那么该promise
状态为rejected
,executor
函数的返回值被忽略。
状态
Promise
本质上就是一个状态机,完整的说是有限状态自动机,给定当前输入与状态,那么输出是可以明确计算的。
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
Promise
对象只有从pending
变为fulfilled
和从pending
变为rejected
的状态改变。只要处于fulfilled
和rejected
,状态就不会再变了。
实现
// 定义_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相关推荐
- 手动实现Promise
基本原理 今天心血来潮,哈哈,就想写个promise对象,需要说的是,我没有参考谁的代码,也没有去看promise的源码,当然,我实现的是一个乞丐版的promise,只有then & catc ...
- 手动实现promise基础功能代码并测试自己写的promise库是否符合规范
promise 解决的问题 回调嵌套/回调地狱 多重异步处理错误捕获不方便 多重异步同步处理的问题 异步并发问题 promise 定义 Promise是一个类 默认浏览器.高版本(ie8以上).nod ...
- 定时器和promise_分析 Promise 内部实现
在介绍Promise之前,首先我们举一个栗子,看下面代码 function success (message) {console.log(message)}function fail (message ...
- 有了async/await,你可以丢掉promise链了
异步函数可能会一直存在,但有些人认为async/await可能会被抛弃. 为什么? 一个常见的误解是async/await和promise是完全不同的东西. 但其实async/await是基于prom ...
- 什么是显式promise构造反模式,如何避免呢?
本文翻译自:What is the explicit promise construction antipattern and how do I avoid it? I was writing cod ...
- 常见 Promise 面试问题
前端面试过程中,基本都会问到 Promise,如果你足够幸运,面试官问的比较浅,仅仅问 Promise 的使用方式,那么恭喜你.事实上,大多数人并没有那么幸运.所以,我们要准备好九浅一深的知识. 常见 ...
- util.promisify 的那些事儿
util.promisify是在node.js 8.x版本中新增的一个工具,用于将老式的Error first callback转换为Promise对象,让老项目改造变得更为轻松. 在官方推出这个工具 ...
- 2019 Web 前端热点笔试面试题总结(转载)
提醒:我只是答案的搬运工,如果在浏览中发现有错误,欢迎评论中提出来,我好修改,谢谢! 简述异步和同步的区别: 同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现 ...
- js中Generator函数详解
文章目录 1. Generator的定义和执行 2. Generator中yield在赋值号左边的情况 3. Generator函数嵌套使用 4. 使用generator函数完成网络请求 1. Gen ...
最新文章
- PHP调试的时候遇到Warning: session_start() [function.session-
- 肝!2500字 字符串专题总结
- Nginx教程-http_core_module变量
- linux+平均磁盘请求数量_Linux 查看磁盘IO并找出占用IO读写很高的进程
- 【docker】常用docker命令,及一些坑
- 三、案例:留言板 url.parse()
- asp.net mvc4使用DropDownList
- [MAC] 小技巧– 取消屏幕缩放功能,以免不小心误触
- 人工智能的未来-揭示人类思维的奥秘How to create a mind - Ray Kurzweil
- 给input设置css样式,input能改变css样式吗
- 将微信数据提取为exel表格(2022年版)免root 保姆级教程
- 第一讲 ISO 17799/27001 标准简介
- 快手、携程等公司转战到 ClickHouse,ES 难道不行了?
- 微信小程序入门---01
- r语言echarts画箱线图_echarter: Echarts的R语言接口
- 接口自动化测试(1)
- hadoop SWAP交换空间
- 局部路径规划算法-DWA动态窗口法
- 光谱响应函数概念与等效遥感反射率的计算
- flash特效原理:标签云