手写promise A+、catch、finally、all、allsettled、any、race

2023-11-29 08:28

本文主要是介绍手写promise A+、catch、finally、all、allsettled、any、race,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

手写promise

同步版

1.Promise的构造方法接收一个executor(),在new Promise()时就立刻执行executor回调

2.executor()内部的异步任务被放入宏/微任务队列,等待执行

3.状态与结果的管理

状态只能变更一次

4.then()调用成功/失败回调

catch是调用失败回调的简写

异步版

1.缓存成功与失败回调

2.then 增加 Pending处理

3.resolve 与 reject 中调用回调函数

多次调用同一个promise的then

1.缓存成功与失败回调 队列

2.pengding时,then()收集依赖,将成功/失败回调放入成功/失败队列

3.触发resolve/reject,从成功/失败队列中取出回调依次执行

then链式调用:返回一个 Promise 对象

then返回自己时,抛错循环调用

等返回的promise初始化好:queueMicrotask微任务

捕获错误

executor错误

then错误

then([onFulfilled, onRejected])参数可选

then 穿透:忽略非函数参数,非函数会同步执行

静态调用resolve、reject

完整版

Promise A+ 规范版的resolvePromise

catch

finally

并发请求

模板

all

allSettled

any

race


手写promise

同步版

1.将promise的resolve和reject函数传给实例用

 constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法executor(this.resolve, this.reject) }

2.实例给resolve和reject函数传值

resolve('success')
reject('err')
// 新建 test.js// 引入我们的 MyPromise.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {resolve('success')reject('err')
})promise.then(value => {console.log('resolve', value)
}, reason => {console.log('reject', reason)
})// 执行结果:resolve success

1.Promise的构造方法接收一个executor(),在new Promise()时就立刻执行executor回调

class Promise{// 构造方法接收一个回调constructor(executor){executor();}

2.executor()内部的异步任务被放入宏/微任务队列,等待执行

  // resolve和reject为什么要用箭头函数?
  // 如果直接调用的话,普通函数this指向的是window或者undefined
  // 用箭头函数就可以让this指向当前实例对象

class MyPromise {constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法executor(this.resolve, this.reject) }// 更改成功后的状态resolve = () => {}// 更改失败后的状态reject = () => {}
}

3.状态与结果的管理

状态只能变更一次
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';// 新建 MyPromise 类
class MyPromise {constructor(executor){...}// 储存状态的变量,初始值是 pendingstatus = PENDING;// 成功之后的值value = null;// 失败之后的原因reason = null;// 更改成功后的状态resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;}}// 更改失败后的状态reject = (reason) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态成功为失败this.status = REJECTED;// 保存失败后的原因this.reason = reason;}}
}

4.then()调用成功/失败回调

catch调用失败回调的简写
// MyPromise.jsthen(onFulfilled, onRejected) {// 判断状态if (this.status === FULFILLED) {// 调用成功回调,并且把值返回onFulfilled(this.value);} else if (this.status === REJECTED) {// 调用失败回调,并且把原因返回onRejected(this.reason);}
}

异步版

// test.jsconst MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {setTimeout(() => {resolve('success')}, 2000); 
})promise.then(value => {console.log('resolve', value)
}, reason => {console.log('reject', reason)
})// 同步版没有打印信息(执行到then时,状态还是pending)
// 异步版等待 2s 输出 resolve success

1.缓存成功与失败回调

// MyPromise 类中新增
// 存储成功回调函数
onFulfilledCallback = null;
// 存储失败回调函数
onRejectedCallback = null;

2.then 增加 Pending处理

// MyPromise.jsthen(onFulfilled, onRejected) {...if (this.status === PENDING) {// ==== 新增 ====// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来// 等到执行成功失败函数的时候再传递this.onFulfilledCallback = onFulfilled;this.onRejectedCallback = onRejected;}
}

3.resolve 与 reject 中调用回调函数

// MyPromise.js// 更改成功后的状态
resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// ==== 新增 ====// 判断成功回调是否存在,如果存在就调用this.onFulfilledCallback && this.onFulfilledCallback(value);}
}

多次调用同一个promise的then

// test.jsconst MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {setTimeout(() => {resolve('success')}, 2000); 
})promise.then(value => {console.log(1)console.log('resolve', value)
})promise.then(value => {console.log(2)console.log('resolve', value)
})promise.then(value => {console.log(3)console.log('resolve', value)
})
//单个回调:3
resolve success
//回调队列:
1
resolve success
2
resolve success
3
resolve success

1.缓存成功与失败回调 队列

// MyPromise.js// 存储成功回调函数
// onFulfilledCallback = null;
onFulfilledCallbacks = [];
// 存储失败回调函数
// onRejectedCallback = null;
onRejectedCallbacks = [];

2.pengding时,then()收集依赖,将成功/失败回调放入成功/失败队列

// MyPromise.jsthen(onFulfilled, onRejected) {// 判断状态if (this.status === FULFILLED) {// 调用成功回调,并且把值返回onFulfilled(this.value);} else if (this.status === REJECTED) {// 调用失败回调,并且把原因返回onRejected(this.reason);} else if (this.status === PENDING) {// ==== 新增 ====// 因为不知道后面状态的变化,这里先将成功回调和失败回调存储起来// 等待后续调用this.onFulfilledCallbacks.push(onFulfilled);this.onRejectedCallbacks.push(onRejected);}
}

3.触发resolve/reject,从成功/失败队列中取出回调依次执行

// MyPromise.js// 更改成功后的状态
resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// ==== 新增 ====// resolve里面将所有成功的回调拿出来执行while (this.onFulfilledCallbacks.length) {// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空this.onFulfilledCallbacks.shift()(value)}}
}

then链式调用:返回一个 Promise 对象

以fulfilled为例,其他同理

// MyPromise.jsclass MyPromise {...then(onFulfilled, onRejected) {// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {// 这里的内容在执行器中,会立即执行if (this.status === FULFILLED) {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(x, resolve, reject);} ...}) return promise2;}
}function resolvePromise(x, resolve, reject) {// 判断x是不是 MyPromise 实例对象if(x instanceof MyPromise) {// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected// x.then(value => resolve(value), reason => reject(reason))// 简化之后x.then(resolve, reject)} else{// 普通值resolve(x)}
}

then返回自己时,抛错循环调用

// test.jsconst promise = new Promise((resolve, reject) => {resolve(100)
})
const p1 = promise.then(value => {console.log(value)return p1
})

function resolvePromise(promise2, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}...
}
等返回的promise初始化好:queueMicrotask微任务

// MyPromise.jsclass MyPromise {......then(onFulfilled, onRejected) {const promise2 = new MyPromise((resolve, reject) => {if (this.status === FULFILLED) {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);})  } ...}) return promise2;}
}

捕获错误

 try {异步操作
} catch (error) {reject(error)
}  

executor错误

// MyPromise.jsconstructor(executor){// ==== 新增 ====// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法try {executor(this.resolve, this.reject)} catch (error) {// 如果有错误,就直接执行 rejectthis.reject(error)}
}

then错误

// MyPromise.jsthen(onFulfilled, onRejected) {// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {// 判断状态if (this.status === FULFILLED) {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)}  })  } ...}) return promise2;
}

then([onFulfilled, onRejected])参数可选

then 穿透:忽略非函数参数,非函数会同步执行

Promise.resolve(1).then(2)//传入值.then(Promise.resolve(3))//传入promise对象.then(console.log)//传入函数
1

Promise.resolve().then(new Promise(r => {setTimeout(() => {r(console.log(1))}, 1000)})).then(new Promise(r => {setTimeout(() => {r(console.log(2))}, 1000)})).then(new Promise(r => {setTimeout(() => {r(console.log(3))}, 1000)}))
延迟1秒后,打印123

不同于下面

// MyPromise.jsthen(onFulfilled, onRejected) {// 如果不传,就使用默认函数onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {......
}

静态调用resolve、reject

// MyPromise.jsMyPromise {......// resolve 静态方法static resolve (parameter) {// 如果传入 MyPromise 就直接返回if (parameter instanceof MyPromise) {return parameter;}// 转成常规方式return new MyPromise(resolve =>  {resolve(parameter);});}// reject 静态方法static reject (reason) {return new MyPromise((resolve, reject) => {reject(reason);});}
}

完整版

// MyPromise.js// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';// 新建 MyPromise 类
class MyPromise {constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法try {executor(this.resolve, this.reject)} catch (error) {this.reject(error)}}// 储存状态的变量,初始值是 pendingstatus = PENDING;// 成功之后的值value = null;// 失败之后的原因reason = null;// 存储成功回调函数onFulfilledCallbacks = [];// 存储失败回调函数onRejectedCallbacks = [];// 更改成功后的状态resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// resolve里面将所有成功的回调拿出来执行while (this.onFulfilledCallbacks.length) {// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空this.onFulfilledCallbacks.shift()(value)}}}// 更改失败后的状态reject = (reason) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态成功为失败this.status = REJECTED;// 保存失败后的原因this.reason = reason;// resolve里面将所有失败的回调拿出来执行while (this.onRejectedCallbacks.length) {this.onRejectedCallbacks.shift()(reason)}}}then(onFulfilled, onRejected) {const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {const fulfilledMicrotask = () =>  {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 获取成功回调函数的执行结果const x = realOnFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)} })  }const rejectedMicrotask = () => { // 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 调用失败回调,并且把原因返回const x = realOnRejected(this.reason);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)} }) }// 判断状态if (this.status === FULFILLED) {fulfilledMicrotask() } else if (this.status === REJECTED) { rejectedMicrotask()} else if (this.status === PENDING) {// 等待// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来// 等到执行成功失败函数的时候再传递this.onFulfilledCallbacks.push(fulfilledMicrotask);this.onRejectedCallbacks.push(rejectedMicrotask);}}) return promise2;}// resolve 静态方法static resolve (parameter) {// 如果传入 MyPromise 就直接返回if (parameter instanceof MyPromise) {return parameter;}// 转成常规方式return new MyPromise(resolve =>  {resolve(parameter);});}// reject 静态方法static reject (reason) {return new MyPromise((resolve, reject) => {reject(reason);});}
}function resolvePromise(promise2, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}// 判断x是不是 MyPromise 实例对象if(x instanceof MyPromise) {// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected// x.then(value => resolve(value), reason => reject(reason))// 简化之后x.then(resolve, reject)} else{// 普通值resolve(x)}
}module.exports = MyPromise;

Promise A+ 规范版的resolvePromise

要求判断 x 是否为 object 或者 function,满足则接着判断 x.then 是否存在,这里可以理解为判断 x 是否为 promise,这里都功能实际与我们手写版本中 x instanceof MyPromise 功能相似

// MyPromise.jsfunction resolvePromise(promise, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise === x) {return reject(new TypeError('The promise and the return value are the same'));}if (typeof x === 'object' || typeof x === 'function') {// x 为 null 直接返回,走后面的逻辑会报错if (x === null) {return resolve(x);}let then;try {// 把 x.then 赋值给 then then = x.then;} catch (error) {// 如果取 x.then 的值时抛出错误 error ,则以 error 为据因拒绝 promisereturn reject(error);}// 如果 then 是函数if (typeof then === 'function') {let called = false;try {then.call(x, // this 指向 x// 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)y => {// 如果 resolvePromise 和 rejectPromise 均被调用,// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用// 实现这条需要前面加一个变量 calledif (called) return;called = true;resolvePromise(promise, y, resolve, reject);},// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promiser => {if (called) return;called = true;reject(r);});} catch (error) {// 如果调用 then 方法抛出了异常 error:// 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回if (called) return;// 否则以 error 为据因拒绝 promisereject(error);}} else {// 如果 then 不是函数,以 x 为参数执行 promiseresolve(x);}} else {// 如果 x 不为对象或者函数,以 x 为参数执行 promiseresolve(x);}
}

catch

//catch方法其实就是执行一下then的第二个回调
catch(rejectFn) {return this.then(undefined, rejectFn)
}

finally

由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况

 finally(callBack) {return this.then(callBack, callBack)}

并发请求

模板

  /*** @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入* @returns */
static 并发(promises) {
// 参数校验
if (Array.isArray(promises)) {let result = []; // 存储结果let count = 0; // 计数器if (promises.length === 0) {
// 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promisereturn resolve(promises);//C. 返回一个 已失败(already rejected) 状态的 Promise。return reject(new AggregateError('All promises were rejected'));}return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中//A.记录所有reject/fulfilled,需要区分状态result[index] = {status: 'fulfilled',value}//B.只记录fulfilledresult[index] = value// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);//C.只要一个成功resolve(value);},reason => {//A.记录所有rejectcount++;result[index] = {status: 'rejected',reason}count === promises.length && resolve(result);//B.一旦rejectreject(reason);     //C.全rejectcount++;errors.push(reason);//AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。count === promises.length && reject(new AggregateError(errors));})})} else {return reject(new TypeError('Argument is not iterable'))
}}

all

/**
* 如果传入的 promise 中有一个失败(rejected),
* Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
*/     
static all(promises) {
return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中result[index] = value;// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);},reason => {reject(reason);                         })})
}

allSettled

static allSettled(promises) {
return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中//A.记录所有reject/fulfilled,需要区分状态result[index] = {status: 'fulfilled',value}// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);},reason => {//A.记录所有rejectcount++;result[index] = {status: 'rejected',reason}count === promises.length && resolve(result);           })})
}

any

static any(promises){return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {//C.只要一个成功resolve(value);},reason => {//C.全rejectcount++;errors.push(reason);//AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。count === promises.length && reject(new AggregateError(errors));})})
}

race

//race方法(返回最早执行完的promise结果,无论成功与否)
Promise.race = function(promises){return new myPromise((resolve, reject) => {// 如果传入的迭代promises是空的,则返回的 promise 将永远等待。if (promises.length > 0) {promises.forEach(item => {myPromise.resolve(item).then(resolve, reject);})}}})

手写实现 Promise 全部实例方法和静态方法,来看看 Promise.all、Promise.race 和 Promise.any 都是怎么实现的 - 掘金

从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节 - 掘金

这篇关于手写promise A+、catch、finally、all、allsettled、any、race的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/432124

相关文章

C++第四十七弹---深入理解异常机制:try, catch, throw全面解析

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】 目录 1.C语言传统的处理错误的方式 2.C++异常概念 3. 异常的使用 3.1 异常的抛出和捕获 3.2 异常的重新抛出 3.3 异常安全 3.4 异常规范 4.自定义异常体系 5.C++标准库的异常体系 1.C语言传统的处理错误的方式 传统的错误处理机制:

stl的sort和手写快排的运行效率哪个比较高?

STL的sort必然要比你自己写的快排要快,因为你自己手写一个这么复杂的sort,那就太闲了。STL的sort是尽量让复杂度维持在O(N log N)的,因此就有了各种的Hybrid sort algorithm。 题主你提到的先quicksort到一定深度之后就转为heapsort,这种是introsort。 每种STL实现使用的算法各有不同,GNU Standard C++ Lib

JS手写实现深拷贝

手写深拷贝 一、通过JSON.stringify二、函数库lodash三、递归实现深拷贝基础递归升级版递归---解决环引用爆栈问题最终版递归---解决其余类型拷贝结果 一、通过JSON.stringify JSON.parse(JSON.stringify(obj))是比较常用的深拷贝方法之一 原理:利用JSON.stringify 将JavaScript对象序列化成为JSO

T1打卡——mnist手写数字识别

🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊 1.定义GPU import tensorflow as tfgpus=tf.config.list_physical_devices("GPU")if gpus:gpu0=gpus[0]tf.config.experimental.set_memort_groth(gpu0,True) #设置GPU现存用量按需

try -catch-finally的理解,同时在try-catch-finally中含有return和throws的理解

在没有try-catch或try-catch-finally的情况下,程序正常执行到某行,在这行报错后,这行后面的代码就不执行了,程序就停止了,中断了。 例如   在有try-catch或try-catch-finally 情况上,在某行执行错误,在try中这行下的代码不执行,try外的代码执行。当然是catch在没有做处理的情况下。如果catch中做了处理,在不影响当前程序下,try

【JavaScript】异步操作:Promise对象

文章目录 1 概述2 Promise 对象的状态3 Promise 构造函数4 Promise.prototype.then()5 then() 用法辨析6 微任务 1 概述 Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。它起到代理作用,充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口。 Promise 的设计思想是,

Promise的使用总结

Promise 是 JavaScript 中用于处理异步操作的一种机制。它提供了一种更清晰和更简洁的方式来处理异步代码,避免了回调地狱。以下是 Promise 的使用方法,包括创建 Promise、链式调用、错误处理、并行执行等。 1. 创建 Promise 你可以使用 new Promise 来创建一个新的 Promise 对象。Promise 构造函数接受一个执行函数,该函数有两个参数:r

【DL--22】实现神经网络算法NeuralNetwork以及手写数字识别

1.NeuralNetwork.py #coding:utf-8import numpy as np#定义双曲函数和他们的导数def tanh(x):return np.tanh(x)def tanh_deriv(x):return 1.0 - np.tanh(x)**2def logistic(x):return 1/(1 + np.exp(-x))def logistic_derivati

【tensorflow CNN】构建cnn网络,识别mnist手写数字识别

#coding:utf8"""构建cnn网络,识别mnistinput conv1 padding max_pool([2,2],strides=[2,2]) conv2 x[-1,28,28,1] 卷积 [5,5,1,32] -> [-1,24,24,32]->[-1,28,

【tensorflow 全连接神经网络】 minist 手写数字识别

主要内容: 使用tensorflow构建一个三层全连接传统神经网络,作为字符识别的多分类器。通过字符图片预测对应的数字,对mnist数据集进行预测。 # coding: utf-8from tensorflow.examples.tutorials.mnist import input_dataimport tensorflow as tfimport matplotlib.pyplot