简单了解
- Promise 主要用来改进异步编程体验
- Promise 有三个状态
pending
、fullfilled
、rejected
, 执行resolve后pending
->fullfilled
fullfilled
的 Promise 实例会转入.then()
处理;rejected
会转入.catch()
处理
promise 类的结构
const PENDING = "pending";
const FULLFILLED = "fullfilled";
const REJECTED = "rejected";
class MyPromise {
constructor(executor) {
this.state = PENDING;
this.val = undefined; // 成功状态promise值
this.reason = undefined; // 失败状态下的promise值
this.onFullfilledCallbacks = []; // 成功回调队列
this.onRejectedCallbacks = []; // 失败回调队列
executor(this.resolve.bind(this), this.reject.bind(this)); // 直接执行promise构造函数
}
resolve(val) {}
reject(reason) {}
then(onfullfilled, onrejected) {}
catch(onrejected) {}
finally(cb) {}
static resolve(arg) {}
static reject(arg) {}
static all(promises) {}
static race(promises) {}
}
resolve
resolve(x) {
if(this.state === PENDING) {
if (x != null && typeof x === "object" && typeof x.then === "function") {
x.then(this.resolve.bind(this), this.reject.bind(this));
}
else {
// pending 状态变成fullfilled状态
this.state = FULLFILLED;
this.val = x;
this.onFullfilledCallbacks.forEach(fn => {
fn(this.val);
});
}
}
}
static resolve
static resolve(arg) {
return new MyPromise((resolve, reject) => {
// 判断 arg是否promise
if(arg !== null && typeof arg ==="object" && typeof arg.then === "function") {
arg.then(resolve, reject);
} else {
resolve(arg);
}
})
}
reject
reject(r) {
if(this.state === PENDING) {
if(r !== null && typeof r === "object" && typeof r.then === "function") {
r.then(this.resolve.bind(this), this.reject.bind(this));
}
else {
// pending 状态变为fullfilled状态
this.state = REJECTED;
this.reason = r;
this.onRejectedCallbacks.forEach(fn => fn(this.reason));
}
}
}
then
then(onfullfilled, onrejected) {
onfullfilled = typeof onfullfilled === "function" ? onfullfilled : value => value;
onrejected = typeof onrejected === "function" ? onrejected : reason => reason;
return new MyPromise((resolve, reject) => {
let fullfilled = value => {
try {
let x = onfullfilled(value);
// x为 MyPromise 或 thenable
if(x !== null && typeof x === "object" && typeof x.then === "function") {
x.then(resolve, reject);
} else {
resolve(x);
}
} catch(err) {
reject(err)
}
}
setTimeout(() => {
if (this.state === PENDING) {
this.onFullfilledCallbacks.push(fullfilled);
this.onRejectedCallbacks.push(rejected);
}else if(this.state === FULLFILLED) {
fullfilled(this.val);
}else {
rejected(this.reason)
}
}, 0);
})
}
finally
finally (cb) {
return this.then((x) => {
// cb 如果 也是 promise
return MyPromise.resolve(cb()).then(() => x);
}, (r) => {
return MyPromise.reject(cb()).then(null, () => x);
});
}
catch
catch (onrejected) {
return this.then(null, onrejected);
}
race
static race (promises) {
return new MyPromise((resolve, reject) => {
for(let i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then((data) => {
resolve(data);
return;
}, (err) => {
reject(err);
return;
});
}
})
}
all
static all(promises) {
return new MyPromise((resolve, reject) => {
let index = 0;
let result = [];
function processValue (i, data) {
result[i] = data;
if(++index === promises.length) {
resolve(result);
}
}
for(let i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then((data) => {
processValue(i, data);
}, (err) => {
reject(err);
return;
});
}
});
}
其它
延迟执行队列
//@vueuse/core useTimeoutFn
async function* makeQueue<T>(jobs: T[], waitGap: number) {
for (const i of jobs) {
await new Promise((resolve) => {
useTimeoutFn(() => {
resolve(true);
}, waitGap);
});
yield i;
}
}
const repeat = (fn: Function, waitGap: number) => {
return async function (arg: Bullet[]) {
for await (const i of makeQueue(arg, waitGap)) {
fn(i);
}
};
};
const repeatPlay = repeat(fn.bind(/* your this*/), 3000);
class Queue{
constructor(){
this.taskList = []
}
task(delay,fn){
function callback(){
return new Promise(function(resolve){
setTimeout(() => {
fn()
resolve()
}, delay);
})
}
this.taskList.push(callback)
return this
}
async start(){
while(this.taskList.length){
await this.taskList.shift()()
}
}
}
new Queue()
.task(1000, () => {
console.log(1)
})
.task(2000, () => {
console.log(2)
})
.task(1000, () => {
console.log(3)
})
.start()