在我开始写直播播放器的时候,由于需要做到最小依赖没有使用第三方的库来管理我的资源,这时候发现我对其的依赖已经到了那么严重。对于普通的应用,下面这套模型应该能够帮助我们统一处理资源问题。 除了promise。
我出现问题的代码
transaction() {
this.timer = setTimeout(() => {
// do something
});
this.interval = setInterval(() => {
// do something
});
window.addEventListener('click', () => {
// oncelogic
})
}
componentWillUnMount() {
if (this.timer) clearTimeout(this.timer);
if (this.interval) clearInterval(this.interval);
window.removeEventListener(...);
}
在一个组件的生命周期内我可能使用了很多类型的资源,但是对于资源的管理却是相当混乱,每一种资源的创建都对应一个特定的释放逻辑。我需要一种统一的模型去处理这些。
所以如果我们用下面这一套模型就会简单很多。
function createTimeout(callback, timeout) {
const timer = setTimeout(callback, timeout);
return () => clearTimeout(timer);
}
function createEventListener(target, type, listener) {
function fun(...args) {
listener.apply(this, args);
}
target.addEventListener(type, fun);
return () => target.removeEventListener(type, fun);
}
这样我们将所有资源的释放逻辑都统一了,我们可以将所有类型的资源都保存在一个数组中,然后统一释放,不需要关心某个资源的释放逻辑。
但是这个模型并不能保证资源只被释放一次,因为组件可以随时释放某些逻辑,所以我们需要一个guard变量来标记是否一个资源已经被释放。
class Subscription {
constructor(teardown) {
if (teardown instanceof Subscription) {
return teardown;
}
this.teardown = teardown;
this.disposed = false;
this._subs = [];
}
add(subOrteardown) {
this._subs = [...this._subs, new Subscription(subOrTeardown)];
}
remove(sub) {
this._subs = this._subs.filter(i => i !== sub);
}
unsubscribe() {
if (!this.disposed && this.teardown) {
this.disposed = true;
this.teardown();
}
this._subs.forEach(sub => sub.unsubscribe());
}
}
这样将所有资源的释放逻辑转换为Subscription
function createTimeout(callback, timeout) {
const timer = setTimeout(callback, timeout);
return new Subscription(() => clearTimeout(timer));
}
function createEventListener(target, type, listener) {
function fun(...args) {
listener.apply(this, args);
}
target.addEventListener(type, fun);
return new Subscription(() => target.removeEventListener(type, fun));
}
程序中就可以统一管理了。
transaction() {
const sub1 = = createTimeout(() => {
// do something
});
const sub2 = createInterval(() => {
// do something
});
const sub3 = createEventListener(...);
this.subscription.add(sub1);
this.subscription.add(sub2);
this.subscription.add(sub3);
}
componentWillUnMount() {
this.subscription.unsubscribe();
}
但是对于Promise却是行不通的,因为Promise一旦创建就不可被取消,除非自己实现一套特别的Promise逻辑,这一点还真是令人头大。
上面根据这些非常清晰的概念,封装到了一个包 tiny-event-manager 中,让小型应用也能很方便地管理资源。