Promise核心实现
核心
构造函数核心
- 维护状态变量,只能由pending变为resolve或者reject
- 维护一个存储结果的变量
- 维护一个回调数组,执行到then,如果我们传入的立即执行函数没有立即执行resolve或者reject,所以promise的状态还是pending,这时要把then里面的回调函数保存起来。待到resolve或者reject执行后则执行回调数组里存到方法。若传入的立即执行函数直接执行了resolve或者reject此时就不用把回调保存起来,直接执行onResolved或onRejected方法。注意是异步执行。而且是做为微任务的。(下面我们用setTimeout模拟)
then核心
- 执行时,若当前状态为pending,则把回调保存到回调数组,若为resolve或者reject则直接异步执行(微任务)。如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。即resolve(result)或者reject(result)
- 每次then都返回一个新的Promise。
- promise会发生值传透,当then中传入的不算函数,则这个then返回的promise的data,将会保存上一个的promise.data。这就是发生值穿透的原因。而且每一个无效的then所返回的promise的状态都为resolved。
核心实现
将Promise向外暴露
- (function (window) {
- /*
- Promise构造函数
- executor:执行器函数
- */
- function Promise(executor) {
- }
- // 向外暴露Promise
- window.Promise = Promise
- })()
构造函数实现
- function MyPromise(exector) {
- var self = this;
- self.status = 'pending'; // 给promise对象指定status属性,初始值为pending
- self.data = undefined; // 给promise对象指定一个存储结果的data
- self.callbacks = []; // 每个元素的结构 {onResolved(){},onRejected(){}}
- function resolve(value) {
- if(self.status !== 'pending') {
- return
- }
- self.status = 'resolved'; // 将状态更改为resolved
- self.data = value; // 保存value的值
- // 异步调用resolve才会在这里执行
- // 如果有待执行的callback函数,立即异步执行回调函数onResolved();
- if(self.callbacks.length > 0) {
- self.callbacks.forEach(callbacksObj => {
- callbacksObj.onResolved(value);
- });
- }
- }
- function reject() {
- // 如果当前状态不是pending,则不执行
- if(self.status !== 'pending'){
- return
- }
- // 将状态改为rejected
- self.status = 'rejected';
- // 保存value的值
- self.data = value;
- // 如果有待执行的callback函数,立即异步执行回调函数onResolved
- if (self.callbacks.length>0){
- self.callbacks.forEach(callbackObj=>{
- callbackObj.onRejected(value)
- })
- }
- }
- // 立即同步执行exector
- // 注意️:当在执行executor的时候,如果执行异常的话,这个promise的状态会直接执行reject方法
- try{
- // 立即同步执行executor
- executor(resolve,reject);
- } catch (e) {
- // 如果执行器抛出异常,promise对象变为rejected状态
- reject(e);
- }
- }
then实现
- MyPromise.prototype.then = function(onResolved, onReject) {
- var self = this;
- // 处理值穿透
- onResolved = typeof onResolved === 'function'? onResolved: value => value
- onRejected = typeof onRejected === 'function'? onRejected: reason => {throw reason}
- return new myPromise((resolve,reject) => {
- if(self.status === 'pending') {
- // promise当前状态还是pending状态,将回调函数保存起来
- self.callbacks.push({
- onResolved() {
- handle(onResolved)
- },
- onRejected() {
- handle(onRejected)
- }
- })
- } else if (self.status === 'resolved') {
- setTimeout(()=>{
- handle(onResolved)
- })
- } else { // 当status === 'rejected'
- setTimeout(()=>{
- handle(onRejected)
- })
- }
- // 处理函数
- function handle(callback) {
- try {
- const result = callback(self.data)
- if (result instanceof MyPromise){
- // 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
- result.then(
- value => {resolve(value)},
- reason => {reject(reason)}
- )
- } else {
- // 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
- resolve(result)
- }
- } catch (e) {
- // 如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected
- reject(e)
- }
- }
- });
- }
其他方法实现
catch
借用then方法
- MyPromise.prototype.catch = function(onRejected){
- return this.then(undefined,onRejected)
- }
finally
借用then方法
- MyPromise.prototype.finally = (onFinally) => {
- return this.then((res)=>{
- MyPromise.resolve(onFinally()).then(()=> res)
- },(reson)=>{
- MyPromise.resolve(onFinally()).then(()=> reson)
- })
- }
resolve
Promise参数可以为如下三种
- 不是promise
- 成功状态的promise
- 失败状态的promise
- MyPromise.resolve = function(value){
- return new MyPromise((resolve,reject)=>{
- if (value instanceof Promise){
- // 如果value 是promise
- value.then(
- value => {resolve(value)},
- reason => {reject(reason)}
- )
- } else{
- // 如果value不是promise
- resolve(value)
- }
- }
- }
reject
- MyPromise.reject = function(reason) {
- return new MyPromise((resolve,reject)=>{
- reject(reason)
- })
- }
all
- 入参一般是个由Promise实例组成的数组,但是也可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。若参数如果不是 Promise 实例,就会先调用Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。
- 返回值是个promise,因为可以使用.then
- 如果全部成功,状态变为resolved, 并且返回值组成一个数组传给回调
- 但凡有一个失败,状态变为rejected, 并将error返回给回调
- MyPromise.all = (promisesArr) => {
- // 返回Promise
- return new MyPromise((resolve, reject) => {
- let dataArr = new Array(promisesArr.length);
- let count = 0;
- for (let i = 0; i < promisesArr.length; i++) {
- // 在 .then 中收集数据,并添加 .catch,在某一个 Promise 遇到错误随时 reject。
- // 这样,在最外面调用 Promise.all().catch() 时也可以 catch 错误信息
- // 判断当前这个元素是否为Promise对象,不是则转为Promise对象
- let currentPromise = (promisesArr[i] instanceof Promise) ? promisesArr[i] : Promise.resolve(promisesArr[i]);
- currentPromise.then(res => {
- dataArr[index] = data;
- count++;
- // 如果数据收集完了,就把收集的数据 resolve 出去
- if (count === promisesArr.length) resolve(dataArr);
- }).catch(err => {
- //如果某一个失败,promise.all()立即执行reject回调。
- //但剩余的promise依旧继续执行,只不过对promise.all的结果不会产生影响了
- reject(err)
- });
- }
- })
注意️:dataArr添加时用下标而不用数组时为了防止顺序错乱
race
返回一个promise对象,状态由第一个完成的promise决定
- MyPromise.race = function(promisesArr){
- return new Promise((resolve,reject)=>{
- // 遍历promises,获取每个promise的结果
- for (let i = 0; i < promisesArr.length; i++) {
- // 判断当前这个元素是否为Promise对象,不是则转为Promise对象
- let currentPromise = (promisesArr[i] instanceof Promise) ? promisesArr[i] : Promise.resolve(promisesArr[i]);
- currentPromise.then(
- value => {
- // 只要有一个成功,返回的promise的状态九尾resolved
- resolve(value)
- },
- reason => { //只要有一个失败,return的promise状态就为reject
- reject(reason)
- }
- )
- })
- })
- }
allSettled
Promise.allSettled() 方法返回一个在所有给定的 promise 已被决议或被拒绝后决议的 promise,并带有一个对象数组,每个对象表示对应的promise 结果。
- Promise.newAllSettled = function (promisesArr) {
- return new Promise((resolve, reject) => {
- let results = [];
- let count = 0;
- let promisesArrLength = promisesArr.length;
- // 运行所有的 Promise
- for (let i = 0; i < promisesArr.length; i++) {
- // 判断当前这个元素是否为Promise对象,不是则转为Promise对象
- let currentPromise = (promisesArr[i] instanceof Promise) ? promisesArr[i] : Promise.resolve(promisesArr[i]);
- currentPromise.then(res => {
- // 当有 Promise 被 resolve 之后,记录 resolve 值和状态,已决 Promise 计数加一
- results.push({value: res, status: 'fulfilled'});
- count++;
- // 全部 Promise 已决,resolve
- if (count === promisesArrLength) {
- resolve(results);
- }
- }).catch(err => {
- // 当有 Promise 被 reject 后,记录 reject 值和状态,并且已决的 Promise 计数加一
- results.push({value: err, status: 'rejected'});
- count++;
- if (count === promisesArrLength) {
- resolve(results);
- }
- });
- }
- })
- };
参考
https://juejin.im/post/6844904088963022856
https://juejin.im/post/6850037281206566919
https://blog.csdn.net/MichelleZhai/article/details/104475521
https://zhuanlan.zhihu.com/p/60287801
https://zhuanlan.zhihu.com/p/41502945
https://zhuanlan.zhihu.com/p/61681036
Promise核心实现的更多相关文章
- Promise核心原理解析
作者: HerryLo 本文永久有效链接: https://github.com/AttemptWeb...... Promises对象被用于表示一个异步操作的最终完成 (或失败), 及其结果值.主要 ...
- promise核心6 自定义promise
1.定义整体结构(不写实现) 定义一个自己的promise的库 lib(库的简写) 一个js文件.一个js模块(不能用es6 也不能commjs)(用es5模块语法 ) 匿名函数自调用.IIFE ( ...
- promise 核心 几个小问题
1.如何改变pending的壮体 抛出异常.pending变为rejected // throw new Error('fail') 内部抛出异常也这样 reason为抛出的error resol ...
- promise核心 为什么用promise
为什么要用promise 1.使用纯回调函数 先指定回调函数,再启动异步任务 答 1.指定回调函数的方式更加灵活 可以在执行任务前,中,后 2.支持链式调用,解决回调地狱问题 什么是回调地狱:回调函数 ...
- Promise核心基础
基础 Promise 抽象表达:是js中进行异步编程的新的解决方案 具体解释:1.从语法上来说是一个构造函数 2.从功能上来说promise对象用来封装一个异步操作并可以获取其结果 状态改变:0.ne ...
- javascript基础修炼(7)——Promise,异步,可靠性
开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一. 别人是开发者,你也是 Promise技术是[javascript异步编程]这个话题中非常重要的,它一度让我感到熟悉 ...
- 分步理解 Promise 的实现
一个 Promise 的运用: var firstPromise = new Promise(function(resolve,reject){ setTimeout(function(){ var ...
- 前端面试?这份手撸Promise请你收下
前言 现在很多大厂面试前端都会要求能够手动的写出一个Promise,所以这里整理了一份手写的Promise. 绝对详细,功能绝对强大.如果你不了解Promise的基本使用,那么本篇文章可能不太适合你, ...
- Generator库co4.6使用及源码分析
原文链接 http://www.cnblogs.com/ytu2010dt/p/6043947.html co4.x已经抛弃了原来thunk转而结合promise实现. 一:promise proms ...
随机推荐
- 2020-06-18:ZK的分布式锁怎么实现?
福哥答案2020-06-18: Zk分布式锁有两种实现方式一种比较简单,应对并发量不是很大的情况.获得锁:创建一个临时节点,比如/lock,如果成功获得锁,如果失败没获得锁,返回false释放锁:删除 ...
- C#LeetCode刷题-字符串
字符串篇 # 题名 刷题 通过率 难度 3 无重复字符的最长子串 24.6% 中等 5 最长回文子串 22.4% 中等 6 Z字形变换 35.8% 中等 8 字符串转整数 (atoi) ...
- notepad++ 设置支持golang语法高亮
see https://stackoverflow.com/questions/27747457/golang-plugin-on-notepad
- HBase存储及读写原理介绍
一.HBase介绍及其特点 HBase是一个开源的非关系型分布式数据库,它参考了谷歌的BigTable建模,实现的编程语言为Java.它是Apache软件基金会的Hadoop项目的一部分,运行于HDF ...
- 攻防世界-web(进阶)-NaNNaNNaNNaN-Batman
用winhex打开,发现是一个javascript代码.将文件重命名为html文件,用浏览器打开. 打开是一个输入框,输入任何东西都梅反应,尝试弹框输入也无果,继续查看代码. 查看代码,可以看到最开始 ...
- 兼容ie9上传本地资源
在ie9中上传文件出现问题,大多数的上传文件都采用new Formdata创建添加文件,在IE9中不支持Formdata对象操作,ie10是支持的.所以只能使用表单提交的方式进行操作. <for ...
- JavaScript学习系列博客_5_JavaScript中的强制类型转换
-强制类型转换为String 1.方式1 调用被转换数据的toString()方法 number类型值.布尔类型值.都可以调用toString()方法强制转换.但是null值和undefined值不行 ...
- C++ Templates (1.6 但是为什么不...? But, Should't We ...?)
返回完整目录 目录 1.6 但是为什么不...? But, Should't We ...? 1.6.1 传值还是传引用? Pass by Value or by Reference? 1.6.2 为 ...
- springMVC入门(四)------参数绑定与返回值类型
简介 从之前的介绍,已经可以使用springMVC完成完整的请求.返回数据的功能. 待解决的问题:如何将数据传入springMVC的控制器进行后续的处理,完成在原生servlet/jsp开发中Http ...
- Sqlalchemy 事件监听与初始化
sqlalchemy不仅仅能自动创建数据库,更提供了其他更强大的功能,今天要介绍的就是sqlalchemy中的事件监听,并将其应用到数据库的初始化中. 需求:当插入设置password字段时,自动加密 ...