【手写promise——基本功能、链式调用、promise.all、promise.race】

这篇具有很好参考价值的文章主要介绍了【手写promise——基本功能、链式调用、promise.all、promise.race】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

关于动机,无论是在工作还是面试中,都会遇到Promise的相关使用和原理,手写Promise也有助于学习设计模式以及代码设计。
本文主要介绍了如何使用自己的代码去实现Promise的一些功能。


以下是本篇文章正文内容

一、前置知识

手写之前,需要知道promise有哪些基本特性:

1、promise有三种状态:pending、fulfilled、rejected。

2、promise的默认状态是pending,状态流转有两种:pending—>fulfilled、pending—>rejected。
【手写promise——基本功能、链式调用、promise.all、promise.race】,javascript,前端,开发语言

3、实例化Promise时,可以接收一个函数作为参数,这个函数有两个参数,分别是resolve、reject方法用于改变实例状态。并能够执行下一个then中的回调函数。
4、then方法中接收两个函数作为参数,第一个函数相当于执行上一个 promise 中执行 resolve 后对应的回调,第二个函数相当于执行上一个 promise 中执行 reject 后对应的回调。

// 1. 实例化 Promise 时
// 可以接收一个函数作为参数,这个函数可以接收到 resolve 和 reject 两个实例方法
// 用于更改当前实例的状态,并把它们接收到的参数传递给下一个 then 对应的参数中
  new Promise((resolve, reject) => {
    // resolve 和 reject 可以都执行,但都执行的意义不大,因为 promise 状态发生更改后,就不能在被更改
    resolve('ok');
    // reject('err');
  }).then((value) => {
    console.log("resolve callback = ", value); // 若执行 resolve,则 value = ok
  }, (reason) => {
    console.log("reject callback = ", reason); // 若执行 reject,则 value = err
  });

5、then操作后会返回一个新的Promise,且支持链式调用。

let promise = new Promise((resolve,reject) => {
    resolve(11)
})
const a = new Promise((resolve,reject) => {
    reject('ok')
})
promise.then(res => {
    console.log(res)
    return a
}).then(res => console.log(res))

6、Promise.all以数组的形式接收多个Promise,当所有Promise执行完成,且状态都为fulfilled时,返回执行成功的结果;有一个失败,则返回失败的结果。

7、Promise.race以数组的形式接收多个Promise,只要有一个Promise先执行成功,无论什么状态,都返回这个结果,给到下一个then中对应的回调。

二、实现基本功能

1、

  • new 操作
  • resolve、reject方法
  • then方法
// 定义三种状态
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class Promise {
    constructor(executor) {

         // 1、默认状态 - PENDING
         this.status = PENDING;
         // 2、内部维护的变量值
         this.value = undefined;
         this.reason = undefined;

        try {
            executor(this.resolve.bind(this), this.reject.bind(this)) // 实例化传进来的函数会立即执行
        } catch(err) {
            this.reject(err)
        }
    }
    resolve(value) {
        if (this.status === PENDING) {
            this.value = value;
            this.status = FULFILLED;
        }
    }
    reject(reason) {
        if (this.status === PENDING) {
            this.reason = reason;
            this.status = REJECTED;
        }
    }
    then(onFulfilled, onRejected) {
        if (onFulfilled && this.status === FULFILLED) {
            let res = onFulfilled(this.value)
            this.resolvePromise(res, resolve, reject)
        }
        if (onRejected && this.status === REJECTED) {
            let res = onRejected(this.reason)
            this.resolvePromise(res, resolve, reject)
        }        
    }
}

通过以下代码自测:

new Promise((resolve,reject) => {
    resolve(1)
}).then(res=> {
	console.log(res) // 1
})

2、考虑异步的情况。
以上代码都是同步的,Promise实例化时传入了异步函数如setTimeout,在setTimeout中resolve,在下一个then的回调函数获取异步函数的状态呢?

我们可以使用回调队列缓存起来,等待执行:

// 定义三种状态
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class Promise {
    constructor(executor) {

         // 1、默认状态 - PENDING
         this.status = PENDING;
         // 2、内部维护的变量值
         this.value = undefined;
         this.reason = undefined;
         this.onResolveCallBack = [];// 缓存 onResolve 
    	 this.onRejectCallBack = [];// 缓存 onReject 

        try {
            executor(this.resolve.bind(this), this.reject.bind(this)) // 实例化传进来的函数会立即执行
        } catch(err) {
            this.reject(err)
        }
    }
    resolve(value) {
        if (this.status === PENDING) {
            this.value = value;
            this.status = FULFILLED;
            // 遍历调用 onResolveCallBack
      		this.onResolveCallBack.forEach(fn => fn());
        }
    }
    reject(reason) {
        if (this.status === PENDING) {
            this.reason = reason;
            this.status = REJECTED;
            this.onResolveCallBack.forEach(fn => fn());
        }
    }
    then(onFulfilled, onRejected) {
        if (onFulfilled && this.status === FULFILLED) {
            let res = onFulfilled(this.value)
            this.resolvePromise(res, resolve, reject)
        }
        if (onRejected && this.status === REJECTED) {
            let res = onRejected(this.reason)
            this.resolvePromise(res, resolve, reject)
        }
        // 当前 promise 状态为 pending,把当前的 onResolve & onReject 缓存起来
        if (this.status === PENDING) {
        	this.onResolveCallBack.push(() => {
        		onResolve(this.value);
        	});	
		    this.onRejectCallBack.push(() => {
		      onReject(this.value);
		    });
  		}       
    }
}

用以下代码测试通过:

 let p = new MyPromise((resolve, reject) => {
      setTimeout(()=>{
        resolve(1);
      },1000);
    }).then(value => {
      console.log('then resolve = ', value);
    }, reason => {
      console.log('then reject = ', reason);
    });
// then resolve = 1

二、实现链式调用

then(onFulfilled, onRejected) {
   	return new Promise((resolve, reject) => { // 支持链式调用
         if (onFulfilled && this.status === FULFILLED) {
             let res = onFulfilled(this.value)
             resolve(res);
         }
         if (onRejected && this.status === REJECTED) {
             let res = onRejected(this.reason)
             resolve(res);
         }
         if (this.status === PENDING) {
             this.onResolvedCallbacks.push(() =>{
                 let res = onFulfilled(this.value)
                 resolve(res);
             })
             this.onRejectedCallbacks.push(() => {
                 let res = onRejected(this.reason)
                 resolve(res);
             })
         }
     })   
 }

测试用例:

let promise = new Promise((resolve,reject) => {
    resolve(1)
})
promise.then(res => {
    return 2 // 返回普通对象
}).then(res => console.log(res)) // 2

如果在then中返回的是普通对象,上述代码能满足,如果返回的是一个Promise,则还需要补充:

then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => { // 支持链式调用
         if (onFulfilled && this.status === FULFILLED) {
             let res = onFulfilled(this.value)
             this.resolvePromise(res, resolve, reject)
         }
         if (onRejected && this.status === REJECTED) {
             let res = onRejected(this.reason)
             this.resolvePromise(res, resolve, reject)
         }
         if (this.status === PENDING) {
             this.onResolvedCallbacks.push(() =>{
                 let res = onFulfilled(this.value)
                 this.resolvePromise(res, resolve, reject)
             })
             this.onRejectedCallbacks.push(() => {
                 let res = onRejected(this.reason)
                 this.resolvePromise(res, resolve, reject)
             })
         }
     })
     
 }
 resolvePromise(res, resolve, reject) {
     if(res instanceof Promise) { // 对then中返回Promise做处理
         res.then(resolve, reject)
       } else{
         // 普通值
         resolve(res)
     }
 }

测试用例:

let promise = new Promise((resolve,reject) => {
    resolve(11)
})
const a = new Promise((resolve,reject) => {
    reject('ok')
})
promise.then(res => {
   return a;
}).then(res => console.log(res)) // ok

三、实现Promise.all

由上述前置知识可知,Promise.all是全部成功才返回成功的结果,有一个失败就返回失败的结果:

Promise.all = function(arr) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(arr)) {
            return reject("参数必须为数组");
        }
        let successNum = 0; // 成功的Promise条数
        let resultArray = [];
        let totalNum = arr.length; // 总Promise数量
        let isFail = false;
        arr.forEach(item => {
            item.then(res => {
                successNum++;
                resultArray.push(res);
                if (successNum === totalNum) { // 说明是全部成功
                    return resolve(resultArray)
                }
            }, err => {
               if (!isFail) reject(err)
               isFail = true;
            })
        });       
    })
}

测试用例:

function wait500(input) {
	return new Promise((resolve, reject) => {
		setTimeout(()=> {
			resolve(500)
		}, 500)
	})
}
function wait1000(input) {
	return new Promise((resolve, reject) => {
		setTimeout(()=> {
			resolve(1000)
		}, 1000)
	})
}
// 全部执行完成之后回调
Promise.all([wait1000(), wait500()]).then(result => {
	console.log('all end', result)
}, err => {
    console.log('fafaf', err)
}) // 'all end [500, 1000]'

四、实现Promise.race

由上述前置知识可知,Promise.race是有一个promise先执行成功,无论什么状态,都返回这个结果:

Promise.race = function(arr) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(arr)) {
            return reject("参数必须为数组");
        }
        arr.forEach(item => {
            item.then(res => {
                return resolve(res); // 状态不可逆,只要其中一个Promise转变了状态,后续状态就不会发生改变
            }, err => {
                reject(err);
            })
        });       
    })

}

测试用例:

function wait500(input) {
	return new Promise((resolve, reject) => {
		setTimeout(()=> {
			resolve(500)
		}, 500)
	})
}
function wait1000(input) {
	return new Promise((resolve, reject) => {
		setTimeout(()=> {
			resolve(1000)
		}, 1000)
	})
}
Promise.race([wait1000(), wait500()]).then(result => {
	console.log('all end', result)
}, err => {
    console.log('fafaf', err)
}) // 打印出'all end 500'

总结

总的代码:文章来源地址https://www.toymoban.com/news/detail-681995.html

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class Promise {
    constructor(executor) {

         // 1、默认状态 - PENDING
         this.status = PENDING;
         // 2、内部维护的变量值
         this.value = undefined;
         this.reason = undefined;

         // 存放回调
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        try {
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch(err) {
            this.reject(err)
        }
    }
    resolve(value) {
        if (this.status === PENDING) {
            this.value = value;
            this.status = FULFILLED;
            this.onResolvedCallbacks.forEach(fn => fn())
        }

    }
    reject(reason) {
        if (this.status === PENDING) {
            this.reason = reason;
            this.status = REJECTED;
            this.onRejectedCallbacks.forEach(fn => fn())
        }
    }
    then(onFulfilled, onRejected) {
        return new Promise((resolve, reject) => { // 支持链式调用
            if (onFulfilled && this.status === FULFILLED) {
                let res = onFulfilled(this.value)
                this.resolvePromise(res, resolve, reject)
            }
            if (onRejected && this.status === REJECTED) {
                let res = onRejected(this.reason)
                this.resolvePromise(res, resolve, reject)
            }
            if (this.status === PENDING) {
                this.onResolvedCallbacks.push(() =>{
                    let res = onFulfilled(this.value)
                    this.resolvePromise(res, resolve, reject)
                })
                this.onRejectedCallbacks.push(() => {
                    let res = onRejected(this.reason)
                    this.resolvePromise(res, resolve, reject)
                })
            }
        })
        
    }
    resolvePromise(res, resolve, reject) {
        if(res instanceof Promise) {
            res.then(resolve, reject)
          } else{
            // 普通值
            resolve(res)
        }
    }
}
// 全部成功才返回成功的结果,有一个失败就返回失败的结果
Promise.all = function(arr) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(arr)) {
            return reject("参数必须为数组");
        }
        let successNum = 0;
        let resultArray = [];
        let totalNum = arr.length;
        let isFail = false;
        arr.forEach(item => {
            item.then(res => {
                successNum++;
                resultArray.push(res);
                if (successNum === totalNum) {
                    return resolve(resultArray)
                }
            }, err => {
                if (!isFail) reject(err)
                isFail = true;
            })
        });       
    })
}

// 某个promise先完成,
Promise.race = function(arr) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(arr)) {
            return reject("参数必须为数组");
        }
        arr.forEach(item => {
            item.then(res => {
                return resolve(res);
            }, err => {
                reject(err);
            })
        });       
    })

}

到了这里,关于【手写promise——基本功能、链式调用、promise.all、promise.race】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • promise的链式调用和promise的嵌套的实现

    话不多说 直接看下面 Promise的链式调用(Chaining)和Promise的嵌套(Nesting)是常见的Promise使用场景,下面我将为您展示它们的实现方法。 链式调用 在链式调用中,我们可以通过多次调用then方法来串联执行多个异步操作。每个then方法都返回一个新的Promise对象,使得我们可以在

    2024年02月15日
    浏览(26)
  • 【JavaScript】手写Promise

    🐱 个人主页: 不叫猫先生 🙋‍♂️ 作者简介:2022年度博客之星前端领域TOP 2,前端领域优质作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫优质专栏:vue3从入门到精通、TypeScript从入门到实践 📢 资料领取:前端进阶资料可以找我免

    2024年02月05日
    浏览(29)
  • 手写Promise的基本实现 (超详细)

    目录 一:首先分析官方的promise 二:手写Promise-then方法设计 三:then方法优化: 四:Promise-catch方法设计  五:Promise-finally方法设计 //本文带大家实现一个基本的 promise 过多的边界情况就不在考虐,理解主要实现过程以及逻辑即可 //对于一个个出现的问题 我会逐步分析原因以及

    2024年02月16日
    浏览(28)
  • 如何在JavaScript中实现链式调用(chaining)?

    前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一

    2024年02月08日
    浏览(28)
  • 【ES6】Promise.race的用法

    Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。 上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。 Promise.race()方法的参数与Promise.all()方法一样,如果不是 Pr

    2024年02月10日
    浏览(28)
  • promise学习1-promise特点,手写简易版promise

    1.promise有三个状态 成功态(resolve) 失败态(reject) 等待态(pending)(既不成功也不失败) 举个例子,女友叫你给她买包 买 不买 不说话 promise就是一个类,所以要new。promise默认为pending状态。 2.用户自己决定成功和失败的原因,也决定最后是否成功还是失败 3.promise默认执

    2024年02月15日
    浏览(27)
  • async/await实现Promise.all()

    🐱个人主页: 不叫猫先生 🙋‍♂️作者简介:专注于前端领域各种技术,热衷分享,期待你的关注。 💫系列专栏:vue3从入门到精通 📝个人签名:不破不立 Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且 只返回

    2024年01月18日
    浏览(34)
  • 【ES6】Promise.all用法

    Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。 上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以

    2024年02月09日
    浏览(27)
  • Vue:使用Promise.all()方法并行执行多个请求

    在Vue中,可以使用Promise.all()方法来并行执行多个请求。当需要同时执行多个异步请求时,可以将这些请求封装为Promise对象并使用Promise.all()方法来执行它们。 示例1: 以下是一个示例代码,展示了如何通过Promise.all()方法并行执行多个请求: 在上述示例中,定义了三个请求:

    2024年02月12日
    浏览(28)
  • 微信小程序-多图片上传(基于Promise.all实现)

    如你所了解到的,微信小程序的wx.uploadFile每次仅支持单文件上传。但在实际的应用场景中往往有多文件上传的需求。因此我打算用Promise.all对wx.uploadFile进行一层封装,让其能够实现多文件上传。 说在前面:若你了解Promise.all的用法.那么你一定知道这样封装的结果: 同时上传多

    2023年04月09日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包