前言
大家好,我是林三心,用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初心。
背景
最近在看一个比较老的工具库源码,学到了一点代码的小技巧,我觉得对于以后的异步操作开发来说挺有用的,所以今天写了一篇文章,分享给大家~
例子
假设,现在有一个类,这个类维护了一个db
对象,但是这个db
对象需要通过异步操作(请求)并拿到结果,来进行初始化,且我们需要用到db
对象上的get
方法,来进行数据的获取,请看下方简易代码~
ts
const request = () => {
return new Promise(resolve => {
// 模拟请求后得到db对象
setTimeout(() => {
resolve({
get: key => key,
});
}, 300);
});
};
class DB {
private db;
constructor() {
this.init();
}
init() {
return request().then(res => {
this.db = res;
});
}
getItem() {
console.log(this.db.get('info'));
}
}
接着我们进行实例的创建,并使用getItem
方法去执行db
对象身上的get
方法,获取我们想要的数据,但是此时会引起报错,说db
不存在
ts
const base = new Base();
base.getItem(); // 报错:this.db 不存在
这是因为db
是通过异步获取的,当你执行getItem
的时候,db
还没初始化完成呢,所以我们得换一种写法我们需要保证init
异步执行完成,再去执行后面的getItem
,这样才不会报错
ts
class Base {
private db;
init() {
return request().then(res => {
this.db = res;
});
}
getItem() {
console.log(this.db.get('info'));
}
}
const fn = async () => {
const base = new Base();
await base.init();
base.getItem(); // 'info'
};
改进
但是这样其实也不是好的做法,按理说init
最好是不要去主动执行,而是应该写在内部,而且把异步init
写在外面,又得套上async
函数,非常麻烦,所以我们换一种写法。
大致思想就是,我们设置一个全局的promise
,这个promise
只有在初始化完成后,状态才会变成成功,才会执行 then
方法,然后对于 db
的操作,全都包裹在这个 promise
的 then
方法中,这样就能保证执行 db
身上方法时,db
已经被初始化完成了~
ts
class Base {
db;
readyPromise;
readyPromiseResolve;
constructor() {
this.init()
}
async init() {
// 全局promise
this.readyPromise = new Promise(resolve => {
// 保存好全局resolve
this.readyPromiseResolve = resolve
})
return request().then(res => {
this.db = res;
// 初始化完成后执行全局resolve
this.readyPromiseResolve()
});
}
ready() {
// 获取全局promise
return this.readyPromise
}
getItem() {
// 全局promise执行then,说明已经初始化完成
// 这时候执行 getItem 就不会报错了
this.ready().then(() => {
console.log(this.db.get('info'));
})
}
}
const base = new Base();
base.getItem() // 'info'
结语 & 加学习群 & 摸鱼群
我是林三心
- 一个待过小型toG型外包公司、大型外包公司、小公司、潜力型创业公司、大公司的作死型前端选手;
- 一个偏前端的全干工程师;
- 一个不正经的掘金作者;
- 一个逗比的B站up主;
- 一个不帅的小红书博主;
- 一个喜欢打铁的篮球菜鸟;
- 一个喜欢历史的乏味少年;
- 一个喜欢rap的五音不全弱鸡
如果你想一起学习前端,一起摸鱼,一起研究简历优化,一起研究面试进步,一起交流历史音乐篮球rap,可以来俺的摸鱼学习群哈哈,点这个,有7000多名前端小伙伴在等着一起学习哦 --> 摸鱼沸点