Open
Description
理解一些基础概念
原型链,类,实例, 类属性,类方法, 实例属性,实例方法
class A {
static b = '1'
static classMethod() {
return 'hello'
}
}
const a = new A();
a.c = 5;
a.sayHello = function() {
console.log('welcome')
}
A: 类
b: 类属性
classMethod: 类方法
a: 实例
a.c: 实例属性
ES6的类
static:静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。
实现一个promise
Promise简介
要想自己实现一个Promise,我们首先要对Promise的用法有所了解;
Promise 是一个构造函数,用来生成 Promise 实例,接受一个函数作为参数,这个函数有两个参数 resolve 和 reject,是两个函数。resolve 是异步操作成功时调用,并将异步操作的结果作为参数传递出去。reject 是异步操作失败时调用,并将异步操作报出的错误作为参数传递出去。
静态属性或方法:是存在类上的属性或方法,实例上无法访问,只用通过 Promise.xxx 访问
要实现 xxx,首先要明白这个函数是干什么的,那又从那个方面来分析么呢?
- 接收哪些参数
- 返回什么参数
- 如果 xxx,怎么处理
Promise 的静态方法
- Promise.resolve()
- Promise.reject()
Promise.resolve()
- 参数:分为以下两种情况
- Promise 实例, 直接返回
- 原始值,或者是一个不具有then方法的对象,返回一个新的 Promise 示例,状态为resolved。
- 返回值:一个新的Promise实例
Promise.reject()
- 参数:分为以下两种情况
- Promise 实例, 直接返回
- 原始值,或者是一个不具有then方法的对象,返回一个新的 Promise 示例,状态为rejected。
- 返回值:一个新的Promise实例
以下方法都是接受数组作为参数,数组中的某项如果不是Promise实例,会先调用Promise.resolve方法,将参数转为 Promise实例,再做处理
- Promise.all()
- Promise.race()
- Promise.allSettled()
- Promise.any()
Promise.all()
- 参数:数组,数组中的某项如果不是Promise实例,会先调用Promise.resolve方法,将参数转为 Promise实例,再做处理
- 返回值:
- 数组:都成功时,返回数组
- 一个 promise 实例:只要有一个失败,返回值为第一个被reject的实例的返回值
Promise.race()
- 参数:数组,数组中的某项如果不是Promise实例,会先调用Promise.resolve方法,将参数转为 Promise实例,再做处理
- 返回值:
- 一个 promise 实例:返回那个率先改变的 Promise 实例的返回值
Promise.allSettled()
-
接收一组 Promise 实例作为参数,只有等到所有的参数实例都返回结果才会返回
-
场景:不关心异步操作的结果,只关心是否都结束了。比如多张图片选择后一起上传时,需要判断多张图片上传的结果,成功了几张,失败了几张
-
参数:数组,数组中的某项如果不是Promise实例,会先调用Promise.resolve方法,将参数转为 Promise实例,再做处理
-
返回值:
- 返回值:数组,数组的每一项都是一个对象具体的结构如下
[ { status: 'fulfilled', value: 1, }, { status: 'rejected', reason: 1, }, ];
Promise.any()
接收一组 Promise 实例作为参数,只要有一个成功就返回成功的结果,如果所有结果都是失败的,就返回所有失败的结果
- 参数:数组,数组中的某项如果不是Promise实例,会先调用Promise.resolve方法,将参数转为 Promise实例,再做处理
- 返回值:
- 一个promise实例:只要有一个成功时返回一个 promise 实例的结果
- 数组:所有都失败时,返回数组
代码实现
class Promise {
constructor(fn) {
/**
* 三种状态
* pending:进行中
* fulfilled:已成功
* rejected: 已失败
*/
this.status = 'pending';
this.resoveList = []; // 成功后回调函数
this.rejectList = []; // 失败后的回调函数
fn(this.resolve.bind(this), this.reject.bind(this));
}
then(scb, fcb) {
if (scb) {
this.resoveList.push(scb);
}
if(fcb) {
this.rejectList.push(fcb);
}
return this;
}
catch(cb) {
if (cb) {
this.rejectList.push(cb);
}
return this;
}
resolve(data) {
if (this.status !== 'pending') return;
this.status = 'fulfilled';
setTimeout(() => {
this.resoveList.forEach(s => {
data = s(data);
})
})
}
reject(err) {
if (this.status !== 'pending') return;
this.status = 'rejected';
setTimeout(() => {
this.rejectList.forEach(f => {
err = f(err);
})
})
}
/**
* 实现Promise.resolve
* 1.参数是一个 Promise 实例, 那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
* 2.如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
*/
static resolve(data) {
if (data instanceof Promise) {
return data;
} else {
return new Promise((resolve, reject) => {
resolve(data);
})
}
}
// 实现Promise.reject
static reject(err) {
if (err instanceof Promise) {
return err;
} else {
return new Promise((resolve, reject) => {
reject(err);
})
}
}
/**
* 实现Promise.all
* 1. Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
* 2. 返回值组成一个数组
*/
static all(promises) {
return new Promise((resolve, reject) => {
let promiseCount = 0;
let promisesLength = promises.length;
let result = [];
for(let i = 0; i < promises.length; i++) {
// promises[i]可能不是Promise类型,可能不存在then方法,中间如果出错,直接返回错误
Promise.resolve(promises[i])
.then(res => {
promiseCount++;
// 注意这是赋值应该用下标去赋值而不是用push,因为毕竟是异步的,哪个promise先完成还不一定
result[i] = res;
if(promiseCount === promisesLength) {
return resolve(result);
}
},(err) => {
return reject(err);
}
)
}
})
}
/**
* 实现Promise.race
* 1. Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
* 2. 返回那个率先改变的 Promise 实例的返回值
*/
static race(promises) {
return new Promise((resolve, reject) => {
for(let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i])
.then(res => {
return resolve(res);
},(err) =>{
return reject(err);
}
)
}
})
}
/**
* Promise.any()
* - 参数:数组,数组中的某项如果不是Promise实例,会先调用Promise.resolve方法,将参数转为 Promise实例,再做处理
- 返回值:
- 一个promise实例:只要有一个成功时返回一个 promise 实例的结果
- 数组:所有都失败时,返回数组
*/
static any(promises) {
return new Promise((resolve, reject) => {
const promisesLen = promises.length;
let promiseCount = 0;
let errorResult = [];
for (let i = 0; i < promisesLen; i++) {
Promise.resolve(promises[i])
.then((value) => {
return resolve(value);
},(err) => {
promiseCount++;
errorResult[i] = err;
if (promiseCount === promisesLen) {
return reject(errorResult);
}
},
);
}
});
}
/**
* Promise.allSettled()
* - 参数:数组,数组中的某项如果不是Promise实例,会先调用Promise.resolve方法,将参数转为 Promise实例,再做处理
* - 返回值:数组
*/
static allSettled(promises) {
return new Promise((resolve, reject) => {
const promisesLen = promises.length;
let promiseCount = 0;
const result = [];
for (let i = 0; i < promisesLen; i++) {
Promise.resolve(promises[i])
.then((value) => {
promiseCount++;
result[i] = {
status: 'fulfilled',
value,
};
if (promiseCount === promisesLen) {
return resolve(result);
}
},(err) => {
promiseCount++;
result[i] = {
status: 'rejected',
reason: err,
};
if (promiseCount === promisesLen) {
return resolve(result);
}
},
);
}
});
}
}
测试用例
1. Promise.then
const p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('resolve');
resolve(222);
}, 1000)
})
p.then(data => {
setTimeout(() => {
console.log('data', data);
})
return 3333;
}).then(data2 => {
console.log('data2', data2);
}).catch(err => {
console.error('err', err);
});
2. Promise.reject
const p1 = Promise.reject('出错了');
p1.then(null, function (s) {
console.log(s); // 出错了
});
3. Promise.all && Promise.race && Promise.any && Promise.allSettled
const q1 = new Promise((resolve, reject) => {
resolve('hello')
});
const q2 = new Promise((resolve, reject) => {
reject('world')
});
Promise.all([q1, q2])
.then((res) => {
console.log(res);
}, (err) => {
console.log(err); // world
});
Promise.race([q1, q2]).then(res => {
console.log(res); // hello
});
Promise.any([q1, q2]).then(res => {
console.log(res); // hello
});
Promise.allSettled([q1, q2]).then(res => {
console.log(res);
/**
[
{ status: 'fulfilled', value: 'hello' },
{ status: 'rejected', reason: 'world' }
]
*/
});