首页IT科技手写promise知乎(300秒带你手写一个promise)

手写promise知乎(300秒带你手写一个promise)

时间2025-05-02 14:38:51分类IT科技浏览4253
导读:前言 为什么要写这一篇文章? 加深对promise的理解,以及再实际工作中的灵活运用。 知其然,知其所以然。 面试需要。(重点!!!)...

前言

为什么要写这一篇文章?

加深对promise的理解          ,以及再实际工作中的灵活运用          。 知其然               ,知其所以然               。 面试需要     。(重点!!!)

1:声明promise

首先我们先来聊聊promise的几个特性:

一个promise有三种状态:pengding,fulfilled     ,rejected. promise状态一旦被改变          ,就不允许被改变了     。 new Promise构造函数接受一个函数参数               ,这个函数有两个参数分别为resole和reject函数               。

其实代码很好写     ,我们就来检验以下resolve的参数是否能正确传递吧

const PENDING = "pengding"; const FUFILLED = "fulfilled"; const REJECTED = "rejected"; class MP { constructor(executor) { this.status = PENDING; this.value = null; executor(this.resolve, this.reject); } resolve(value) { this.value = value; console.log("resolve:" + this.value); } reject(season) {} } // test new MP((resolve, reject) => { resolve("你好"); });

打开控制台     ,我们发现无法设置属性value,

查看代码我们很容易发现其实代码this绑定的问题               ,我们用bind绑定以下就好了          。

this问题解决了          ,但是还有一个问题     ,状态只能改变一次     。所以我们在resolve和reject函数执行的时候要判断一下状态               。

const PENDING = "pengding"; const FUFILLED = "fulfilled"; const REJECTED = "rejected"; class MP { constructor(executor) { this.status = PENDING; this.value = null; executor(this.resolve.bind(this), this.reject.bind(this)); } resolve(value) { if(this.status == PENDING){ this.status = FUFILLED; this.value = value; console.log("resolve:" + this.value); } } reject(season) { if (this.status == PENDING) { this.status = REJECTED; this.value = season; console.log("reject:" + this.value); } } } // test new MP((resolve, reject) => { resolve("你好"); });

2:then的基础构建

2.1:then的用法

接受两个参数               ,当promise成功执行第一个函数参数          ,失败执行第二个函数参数          。 then里面也可以不传参数。 then里面的函数为异步操作               。(promise是微任务) then(onFulfilled, onRejected) { // 判断两个参数是不是函数类型,如果不是函数               ,需要手动封装               ,否则下面执行时会报错               。 if (typeof onFulfilled !== "function") { onFulfilled = () => {}; } else if (typeof onRejected !== "function") { onRejected = () => {}; } if (this.status === "fulfilled") { onFulfilled(this.value); } else if (this.status === "rejected") { onRejected(this.value); } else { } } // test new MP((resolve, reject) => { resolve("你好"); }).then( res => { console.log("then res", res); }, rej => { console.log(rej); } );

then可以接收到resolve传过来的数据。

2.2:异步操作(任务队列不懂的先去学学)

这里我们使用queueMicrotask来创建微任务:

then(onFulfilled, onRejected) { // 判断两个参数是不是函数类型,如果不是函数          ,需要手动封装               ,否则下面执行时会报错          。 if (typeof onFulfilled !== "function") { onFulfilled = () => {}; } else if (typeof onRejected !== "function") { onRejected = () => {}; } if (this.status === "fulfilled") { queueMicrotask(()=>{ onFulfilled(this.value); }); } else if (this.status === "rejected") { queueMicrotask(()=>{ onRejected(this.value); }); ; } else { } } } // test new MP((resolve, reject) => { resolve("中国"); console.log(你好); }).then(res=>{ console.log(res) });

顺序是正确的     ,同步任务打印的你好优先于异步任务打印的中国               。

2.3:then处理pengding状态

当我们在执行then方式的时候          ,状态还是没有改变的情况     。(什么情况状态没有改变:异步执行resolve或者reject的时候 )之前的代码只判断了fulfilled和rejected的状态          。

// test new MP((resolve, reject) => { setTimeout(() => { resolve("异步操作"); },1000); }).then(res=>{ console.log(res); });

这个时候控制台是不答应任何东西的               ,因为还没有处理这个状态               。所以说我们之前的思路就有一点问题     ,在then函数中我们不应该控制then里面的两个参数函数的执行     ,应该去保存它               ,在resolve和reject方式再去执行     。

const PENDING = "pengding"; const FUFILLED = "fulfilled"; const REJECTED = "rejected"; class MP { constructor(executor) { this.status = PENDING; this.value = null; // 将回调函数保存起来 this.callbacks = []; executor(this.resolve.bind(this), this.reject.bind(this)); } resolve(value) { if (this.status == PENDING) { let that = this; this.status = FUFILLED; this.value = value; // // 触发回调函数 queueMicrotask(() => { that.callbacks.map(callback => { callback.onFulfilled(that.value); }); }); } } reject(season) { if (this.status == PENDING) { let that = this; this.status = REJECTED; this.value = season; // 触发回调函数 queueMicrotask(() => { that.callbacks.map(callback => { callback.onRejected(that.value); }); }); } } then(onFulfilled, onRejected) { // 判断两个参数是不是函数类型          ,如果不是函数     ,需要手动封装               ,否则下面执行时会报错     。 if (typeof onFulfilled !== "function") { onFulfilled = () => {}; } else if (typeof onRejected !== "function") { onRejected = () => {}; } if (this.status === "fulfilled") { // 收集回调函数 this.callbacks.push({ onFulfilled }); } else if (this.status === "rejected") { // 收集回调函数 this.callbacks.push({ onRejected }); } else { // 收集回调函数 this.callbacks.push({ onFulfilled, onRejected }); } } }

2.4:then链式调用

then返回的也是一个promise 之前promise的状态不会影响新的promise状态               。

所以我们现在要继续处理我们的then方法          ,首先在then函数里肯定要返回一个promise的,其次在then函数里面我们要拿到onFulfilled, onRejected这两个回调函数的结果               ,作为这个新的promise的值          。

then(onFulfilled, onRejected) { // 判断两个参数是不是函数类型               ,如果不是函数,需要手动封装          ,否则下面执行时会报错     。 if (typeof onFulfilled !== "function") { onFulfilled = () => {}; } else if (typeof onRejected !== "function") { onRejected = () => {}; } // 直接返回一个新的promise 之前在then里面处理的代码迁移到新的promise里面处理 return new MP((resolve,reject)=>{ // 这时里面的this指向的不是新的promise if (this.status === "fulfilled") { this.callbacks.push({ // 这个改成箭头函数的形式               ,方便我们获取onFulfilled的值传递给新promise的resolve onFulfilled:value=>{ let result = onFulfilled(value) resolve(result) } }); } else if (this.status === "rejected") { this.callbacks.push({ onRejected:value=>{ let result = onRejected(value); resolve(result); } }); } else { this.callbacks.push({ onFulfilled: value => { onFulfilled(value); }, onRejected: value => { onRejected(value); } }); } }) } // test new MP((resolve, reject) => { resolve("异步操作"); }).then( res => { return 33333; }, rej => {return 11111111} ).then(res=>{ console.log(res) });

在第二个then打印的结果应该是第一个then中返回的33333

2.5:then回调函数返回promise

new Promise((res,rej)=>{ res(1111) }).then(res=>{ return new Promise((res,rej)=>{ res(22222) }) }).then(res=>{ console.log(res) });

打印结果应该为22222而不是promise对象               。

用我们手写的试试

new MP((resolve, reject) => { resolve("异步操作"); }).then( res=>{ return new MP((res, rej) => { res("22222"); }); } ).then(res=>{ console.log(res) });

返回的却是一个promise对象     ,这是因为我们在处理回调函数结果时          ,没有判断类型               ,直接将整个result都返回给下个then了     ,所以我们在返回之前     ,需要判断以下返回的结果          。

then(onFulfilled, onRejected) { // 判断两个参数是不是函数类型               ,如果不是函数          ,需要手动封装     ,否则下面执行时会报错。 if (typeof onFulfilled !== "function") { onFulfilled = () => {}; } else if (typeof onRejected !== "function") { onRejected = () => {}; } return new MP((resolve,reject)=>{ if (this.status === "fulfilled") { this.callbacks.push({ onFulfilled:value=>{ let result = onFulfilled(value); // 结果时MP类型时 if(result instanceof MP){ // 我们可以直接通过这个promise的then方法来传递值 result.then(resolve, reject); }else{ resolve(result); } } }); } else if (this.status === "rejected") { this.callbacks.push({ onRejected:value=>{ let result = onRejected(value); // 结果时MP类型时 if (result instanceof MP) { result.then(resolve, reject); } else { resolve(result); } } }); } else { this.callbacks.push({ onFulfilled: value => { let result = onFulfilled(value); // 结果时MP类型时 if (result instanceof MP) { result.then(resolve, reject); } else { resolve(result); } }, onRejected: value => { let result = onRejected(value); // 结果时MP类型时 if (result instanceof MP) { result.then(resolve, reject); } else { resolve(result); } } }); } }) }

打开控制台就是具体的值而不是promise.

2.6:prmise返回类型约束

看一段代码

let promise = new Promise((res,rej)=>{ res(111) }) let p = promise.then(res=>{ return p })

我们发现控制台报错了               ,说明promise不能返回自己          ,对于返回类型是有约束的.

then(onFulfilled, onRejected) { // 判断两个参数是不是函数类型,如果不是函数               ,需要手动封装               ,否则下面执行时会报错               。 if (typeof onFulfilled !== "function") { onFulfilled = () => {}; } else if (typeof onRejected !== "function") { onRejected = () => {}; } let promise = new MP((resolve,reject)=>{ if (this.status === "fulfilled") { this.callbacks.push({ onFulfilled:value=>{ let result = onFulfilled(value); if(result === promise){ throw new TypeError( "Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>" ); } // 结果时MP类型时 if(result instanceof MP){ result.then(resolve, reject); }else{ resolve(result); } } }); } else if (this.status === "rejected") { this.callbacks.push({ onRejected:value=>{ let result = onRejected(value); // 判断返回类型 if (result === promise) { throw new TypeError( "Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>" ); } // 结果时MP类型时 if (result instanceof MP) { result.then(resolve, reject); } else { resolve(result); } } }); } else { this.callbacks.push({ onFulfilled: value => { let result = onFulfilled(value); if (result === promise) { throw new TypeError( "Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>" ); } // 结果时MP类型时 if (result instanceof MP) { result.then(resolve, reject); } else { resolve(result); } }, onRejected: value => { let result = onRejected(value); if (result === promise) { throw new TypeError( "Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>" ); } // 结果时MP类型时 if (result instanceof MP) { result.then(resolve, reject); } else { resolve(result); } } }); } }) return promise }

3:实现Promise.resolve和Promise.reject

例子:

Promise.resolve(111).then(res=>{ console.log(res) }) Promise.reject(111).then(res=>{ console.log(res) },rej=>{ console.log(rej) })

其实这个方法就是帮助我们做了两件事情

创建一个promise 将promise的状态设置成功或者失败 static resolve(value){ return new MP(resolve => { if (value instanceof MP) { value.then(resolve); } else { resolve(value); } }); }

reject同理就不用写了哈               。

4:实现Promise.all

Promise.all方法会返回一个promise,当参数数组中所有promise都成功后,就会返回成功的promise.看到所有时          ,我们就需要一个计数器               ,每次成功一个记录一次     ,当记录结果和传入数组长度一样时          ,就返回成功的               ,当一个失败时     ,就直接返回失败的。

static all(promises){ let length = promises.length; // 记录每个promise成功时结果     ,同时用于返回 let arr = []; return new MP((resolve, reject) => { for (let i = 0; i < length; i++) { promises[i].then( res => { arr[i] = res; if (arr.length === length) { resolve(arr); } }, rej => { reject(rej); } ); } }); }

结尾

喜欢的小伙伴可以点赞收藏哈               ,有没有一起备战面试的          ,大家一起加油哈~

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
网站曝光率指能让更多的客户在搜索引擎或网站(提升网站曝光率的必备法宝——网站目录收录) 网站收录率一般多高(提升网站曝光率的必备利器——网站收录查询工具)