木灵鱼儿
阅读:915
手写Promise
/*
* @Author: mulingyuer
* @Date: 2021-12-30 22:06:58
* @LastEditTime: 2022-01-03 05:22:30
* @LastEditors: mulingyuer
* @Description: 手写promise
* @FilePath: \undefinedc:\Users\13219\Desktop\promise.js
* 怎么可能会有bug!!!
*/
/**
* @description: 自定义promise
* @param {fucntion} executor 执行器函数(同步执行)
* @Date: 2022-01-03 03:02:58
* @Author: mulingyuer
*/
class MyPromise {
status = ""; //状态
value = null; //值
callbacks = []; //存储回调,结构:{onResolved,onRejected}
//状态
static PEDDING = "pedding";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.status = MyPromise.PEDDING;
//运行执行器并捕获错误
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
/**
* @description: resolve
* @param {*} value
* @Date: 2022-01-03 03:16:33
* @Author: mulingyuer
*/
resolve(value) {
if (this.status !== MyPromise.PEDDING) return;
//改变状态
this.status = MyPromise.FULFILLED;
//保存数据
this.value = value;
//运行回调,使用宏队列模拟微队列
if (this.callbacks.length > 0) {
setTimeout(() => {
this.callbacks.forEach(item => {
item.onResolved(this.value);
})
})
}
}
/**
* @description: reject
* @param {*} reason
* @Date: 2022-01-03 03:16:55
* @Author: mulingyuer
*/
reject(reason) {
if (this.status !== MyPromise.PEDDING) return;
//改变状态
this.status = MyPromise.REJECTED;
//保存数据
this.value = reason;
//运行回调,使用宏队列模拟微队列
if (this.callbacks.length > 0) {
setTimeout(() => {
this.callbacks.forEach(item => {
item.onRejected(this.value);
})
})
}
}
/**
* @description: then方法,并返回一个新的promise对象
* @param {function} onResolved 成功的回调
* @param {function} onRejected 失败的回调
* @Date: 2022-01-03 03:04:00
* @Author: mulingyuer
*/
then(onResolved, onRejected) {
//默认处理,参数必须是函数
onResolved = typeof onResolved === "function" ? onResolved : value => value; //默认值进行传递
onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason }; //默认值进行传递
return new MyPromise((resolve, reject) => {
//通用处理状态的方法:如果返回的值是promise,则根据promise的结果改变状态,否则默认resolve
function handle(callback) {
try {
const result = callback(this.value);
//如果返回的值是promise,则根据promise的结果改变状态,否则默认resolve
if (result instanceof MyPromise) {
return result.then(resolve, reject);
} else {
return resolve(result);
}
} catch (error) {
return reject(error);
}
}
//pedding状态保存回调
if (this.status === MyPromise.PEDDING) {
this.callbacks.push({
onResolved: () => {
handle.call(this, onResolved);
},
onRejected: () => {
handle.call(this, onRejected);
}
});
}
//成功状态
if (this.status === MyPromise.FULFILLED) {
setTimeout(() => {
handle.call(this, onResolved);
})
}
//失败状态
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
handle.call(this, onRejected);
})
}
});
}
/**
* @description: catch 方法
* @param {function} onRejected 失败的回调
* @Date: 2022-01-03 03:04:48
* @Author: mulingyuer
*/
catch(onRejected) {
return this.then(null, onRejected);
}
/**
* @description: 函数对象的resolve方法
* @param {*} value
* @Date: 2022-01-03 03:05:31
* @Author: mulingyuer
*/
static resolve(value) {
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise) {
return value.then(resolve, reject);
} else {
return resolve(value);
}
})
}
/**
* @description: 函数对象的reject方法
* @param {*} reason
* @Date: 2022-01-03 03:06:42
* @Author: mulingyuer
*/
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason));
}
/**
* @description: 函数对象all方法
* @param {array} promises promise数组
* @Date: 2022-01-03 03:07:08
* @Author: mulingyuer
*/
static all(promises) {
//创建一个对应数量的空数组
const arr = new Array(promises.length);
//计数器
let count = 0;
//返回一个promise
return new MyPromise((resolve, reject) => {
promises.forEach((item, index) => {
MyPromise.resolve(item).then(
res => {
count++;
//根据位置保存数据
arr[index] = res;
//判断是否完成
if (count === promises.length) {
return resolve(arr);
}
},
err => {
return reject(err);
}
)
});
});
}
/**
* @description: 函数对象race方法
* @param {array} promises promise数组
* @Date: 2022-01-03 03:07:47
* @Author: mulingyuer
*/
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(item => {
MyPromise.resolve(item).then(resolve, reject);
})
})
}
/**
* @description: 延迟指定时间返回成功的promise
* @param {*} value
* @param {number} time
* @Date: 2022-01-03 05:19:36
* @Author: mulingyuer
*/
static resolveDelay(value, time) {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if (value instanceof MyPromise) {
return value.then(resolve, reject);
} else {
return resolve(value);
}
}, time)
});
}
/**
* @description: 延迟指定时间返回错误的promise
* @param {*} reason
* @param {number} time
* @Date: 2022-01-03 05:21:52
* @Author: mulingyuer
*/
static rejectDelay(reason, time) {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
return reject(reason);
}, time)
})
}
}
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
Event Loop事件队列和宏任务微任务
Event Loop我们知道JavaScript是一门单线程的语言,他只能一行一行的执行代码,于是我们的代码应该都是同步的,这里我们暂时忘掉所有的异步,看一下这么做会有什么问题。用户进入了我们的网页,点击了一个按钮,触发加载更多功能,此时浏览器发起ajax请求,如果我们的代码都是同步的,那么页面会在这个请求完成之前是卡主状态的,因为需要等待该代码的完成,此时用户什么都做不了,既不能滚动页面,也无法点击其他内容,如果这个请求需要60s的时间,用户肯定会觉得,这是什么狗屎页面。这显然是不行的,因为代码阻塞导致体验特别的差,解决这个问题的办法就是加入异步功能,我们将请求的回调作为异步处理,不需...

Promise失败重试,可指定重试次数
//模拟异步请求 function axiosFn() { return new Promise((resolve, reject) => { const flge = Math.random(); //随机值 setTimeout(() => { //大于0.7就是成功 if (flge > 0.7) { return resolve(flge); } else { return reject(...
animation 动画的三个事件
const div = document.querySelector("div.box"); div.addEventListener("animationstart", function() { //动画开始运行触发 }); div.addEventListener("animationiteration", function() { //动画每执行一次触发一次,适用用多次动画 }); div.addEventListener("animationend", function() { //...
promise 队列
数组map实现function fn1() { return new Promise((resolve, reject) => { setTimeout(() => { console.log(1); resolve(); }, 500) }) } function fn2() { return new Promise((resolve, reject) => { setTimeout(() => { console.l...
利用Promise实现一个超时结束等待操作
promise如果没有指定状态,那么就一直会处于pending中,如果长时间不处理,那么这个东西会一直存在于内存中,显然是不合理的。如果是一个超多请求项目,那么我们就需要考虑下性能问题了。promise中有一个rece方法,它接收一个promise作为值的数组,它的特性就是:哪个promise先执行,他就处理那一个,不管是resolve还是reject;在then中,他也只有一个值,不同于Promise.all方法返回的是一个数组,rece返回的值是最快完成的那个promise的返回值。利用这个特性,我们可以制作一个超时处理。function delayPromise(promise, ...
深度合并对象的方法
找了很久,现有的库有两个:1. Mergenpm地址: Merge用法:import merge from 'merge'; const obj1 = { name: 2}; const obj2 = { value: 1 }; //合并 merge(obj1,obj2); console.log(obj1); //{name:2,value:1} //克隆合并-与目标对象无关联 const obj3 = merge(true,obj1,obj2); console.log(obj3); //{name:2,value:1} console.log(obj3 === obj1)...
利用JSON过滤对象和数组中指定的key属性
有时候我们在vue中进行for循环,就会涉及到绑定唯一值key的问题,但是并不是任何时候都会存在所谓的唯一值,使用index下标明显是不合适的,官方也不推荐,除非你for循环出来的列表不用变化。所以一般常用的做法就是给for循环的对象添加一个属性,属性的值是随机的uuid或者时间戳。这样前端问题解决了,如果遍历的数据还需要提交到后端,那么不就多了一个属性,这个属性后端不需要的。所以,我们需要在提交数据前,对数据进行过滤。过滤又得for循环删除?那怎么行,有没有那种通用的,简单的方法。过滤方法/** * @description: 过滤对象中指定的属性,也可以拿来浅拷贝 * @para...
Copy 一个复制操作的类
前言js有一个31k多的star的开源复制库:clipboard.js;但是一些简单复制并不想安装一个库来解决,所以就想自己写一个。copy所需要的东西Selection 对象用于获取被用户选中的部分,通过toString()方法可以获取被选中的文本内容,以及js操作选中。MDN文档:SelectionexecCommand 对象用于以命令的形式来操作网页的内容,说白了就是用它来实现复制文本操作,复制的是选中的文本MDN文档:execCommand 需要注意的是,execCommand在未来将会被遗弃,因为这个api本身是从ie浏览器那边继承的,久而久之各大浏览器都对其做了兼容,虽然...