记录一下前端学习笔记,每天打卡!! 目标:
必知必会: js | 布局样式 | 客户端 | 技术栈
加分项:工具(CI/CD等) 热门模块工程化
进阶:模式 实战/算法
开始第三天知识学习
promise
promise解决了回调地狱
手写promise
enum PromiseStatus {
PENDING = 'pending',
FULFILLED = 'fulfilled',
REJECT = 'reject'
}
class MyPromise<T = any>{
status = PromiseStatus.PENDING
value: T
reason: any
// then回调函数的队列
onFulfilledFns = new Array<(value: T) => void>()
onRejectedFns = new Array<(reason: any) => void>()
constructor(executor: (
resolve: (value: T) => void,
reject: (value: T) => void) => void) {
const resolve = (value: T) => {
if (this.status === PromiseStatus.PENDING) {
queueMicrotask(() => {
if (this.status !== PromiseStatus.PENDING) return
this.status = PromiseStatus.FULFILLED
this.value = value
this.onFulfilledFns.forEach(fn => fn(this.value))
})
}
}
const reject = (reason: any) => {
if (this.status === PromiseStatus.PENDING) {
queueMicrotask(() => {
if (this.status !== PromiseStatus.PENDING) return
this.status = PromiseStatus.REJECT
this.reason = reason
this.onRejectedFns.forEach(fn => fn(this.value))
})
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(
onFulfilled: (value: T) => any = (value) => value,
onRejected: (reason: any) => any = (reason) => reason) {
return new MyPromise((resolve, reject) => {
// 如果当前Promise状态为已知
if (this.status === PromiseStatus.FULFILLED) {
try {
const res = onFulfilled(this.value)
resolve(res)
} catch (error) {
reject(error)
}
}
if (this.status === PromiseStatus.REJECT) {
try {
const res = onRejected(this.reason)
resolve(res)
} catch (error) {
reject(error)
}
}
// 如果当前Promise状态未知
if (this.status === PromiseStatus.PENDING) {
this.onFulfilledFns.push(() => {
try {
const res = onFulfilled(this.value)
resolve(res)
} catch (error) {
reject(error)
}
})
this.onRejectedFns.push(() => {
try {
const res = onRejected(this.reason)
resolve(res)
} catch (error) {
reject(error)
}
})
}
})
}
catch(onRejected: (reason: any) => any = (reason) => reason) {
return this.then(undefined, onRejected)
}
finally(onFinally: () => void) {
return this.then(() => onFinally, () => onFinally)
}
static resolve<T>(value: T) {
return new MyPromise<T>(resolve => resolve(value))
}
static reject(reason: any) {
return new MyPromise((resolve, reject) => reject(reason))
}
static all(promises: Array<MyPromise>): MyPromise<any[]> {
return new MyPromise((resolve, reject) => {
const values: any[] = []
let finishCount = 0
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
values[i] = res
finishCount++
if (finishCount == promises.length) {
resolve(values)
}
}), err => {
reject(err)
}
}
})
}
}
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log("--- 1 ---");
resolve(111);
});
}).then(res => {
console.log("p1 res :>> ", res);
});
const p2 = new MyPromise((resolve, reject) => {
console.log("--- 2 ---");
resolve(222);
});
const p3 = new MyPromise((resolve, reject) => {
console.log("--- 3 ---");
resolve(333);
});
思考:有没有像写同步的代码,来写异步呢?
Generator函数
import fsp from 'fs/promises';
function* func() {
const res1 = yield fsp.readFile("test1.txt")
console.log(res1.toString())
const res2 = yield fsp.readFile("text2.txt")
console.log(res2.toString());
const res3 = yield fsp.readFile("text3.txt")
console.log(res3.toString())
return
}
const g = func()
// g.next()
g.next().value.then(data => {
g.next(data).value.then(data => {
g.next(data).value.then(data => {
g.next(data)
})
})
})
如上所述,虽然读取文件的异步操作写成了同步的方式,但是下面调用的方式还是回调的方式,有咩有更好的方法呢? 可以改成递归的方式。
function run(gen: () => Generator<Promise<Buffer>, void, unknown>) {
const g = gen()
function next(data?: any) {
const result = g.next(data)
if (result.done) return
result.value.then(data => next(data))
}
next()
}
run(func)
这样就是解决异步的比较好的方法,其实后面ES6的async和await就是Generator和yield的语法糖,所以上面可以写成如下:
import fsp from 'fs/promises';
async function func() {
const res1 = await fsp.readFile("test1.txt")
console.log(res1.toString())
const res2 = await fsp.readFile("text2.txt")
console.log(res2.toString());
const res3 = await fsp.readFile("text3.txt")
console.log(res3.toString())
return
}
func()
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
由上,可知道async和await不仅是Generator和yield的语法糖,同时还对错误异常进行了处理,是比较好的异步处理方式。