@vitarx/responsive
Version:
Vitarx responsive package
179 lines (178 loc) • 5.62 kB
JavaScript
import { getContext, runInContext } from '../context/index.js';
import { Effect, isEffect } from './effect.js';
/**
* 作用域管理器类,用于管理和控制副作用的生命周期
*
* @extends {Effect}
*/
export class EffectScope extends Effect {
/**
* 创建一个新的作用域管理器实例
*
* @param {EffectScopeOptions} [options] - 作用域配置选项
* @throws {TypeError} 当errorHandler不是函数类型时抛出
*/
constructor(options) {
super();
/**
* 作用域配置对象,包含所有配置项的必填版本
*
* @public
* @readonly
*/
Object.defineProperty(this, "config", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
/**
* 存储当前作用域管理的所有副作用对象的集合
*
* @private
*/
Object.defineProperty(this, "_effectSet", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.config = Object.assign({ attachToCurrentScope: false, name: 'anonymous', errorHandler: null }, options);
if (this.config.errorHandler && typeof this.config.errorHandler !== 'function') {
throw new TypeError('[Vitarx.EffectScope]: The errorHandler must be a function type');
}
if (this.config.attachToCurrentScope)
EffectScope.getCurrentScope()?.addEffect(this);
}
/**
* 获取作用域名称
*
* @returns {string | symbol} 作用域名称
*/
get name() {
return this.config.name;
}
/**
* 获取当前作用域中的副作用数量
*
* @returns {number} 副作用数量
* @readonly
*/
get count() {
return this._effectSet?.size ?? 0;
}
/**
* 获取当前上下文中的作用域实例
*
* @returns {EffectScope | undefined} 当前作用域实例,如果不存在则返回undefined
* @static
*/
static getCurrentScope() {
return getContext(EffectScope.contextTag);
}
/**
* 在当前作用域上下文中运行函数并捕获其产生的副作用
*
* @template T - 函数返回值类型
* @param {() => T} fn - 要执行的函数
* @returns {T} 函数的返回值
* @throws {Error} 当函数执行出错时抛出
* @remarks
* 如果函数内部存在异步操作(await),需要使用`withAsyncContext` API维护上下文,
* 否则在await之后的副作用将无法被正确捕获
*/
run(fn) {
return runInContext(EffectScope.contextTag, this, fn);
}
/**
* 向作用域中添加一个可处置的副作用对象
*
* @param {EffectInterface} effect - 要添加的副作用对象
* @returns {EffectScope} 当前作用域实例,用于链式调用
* @throws {Error} 当作用域已经被销毁时抛出
* @throws {TypeError} 当effect不是有效的副作用对象时抛出
*/
addEffect(effect) {
if (this.isDeprecated) {
throw new Error('[Vitarx.EffectScope]: Cannot add effects to a destroyed scope');
}
if (!isEffect(effect)) {
throw new TypeError('[Vitarx.EffectScope]: Effect objects must implement the EffectInterface');
}
if (this.config.errorHandler && effect.onError) {
effect.onError(this.config.errorHandler);
}
if (!this._effectSet) {
this._effectSet = new Set([effect]);
}
else {
this._effectSet.add(effect);
}
effect.onDispose(() => this._effectSet?.delete(effect));
return this;
}
/**
* 销毁作用域并清理所有副作用
* 此操作会触发所有副作用的dispose方法,并清空内部存储
*
* @returns {boolean} 操作结果,如果操作成功则返回true,否则返回false
* @override
*/
dispose() {
if (super.dispose()) {
this._effectSet?.forEach(effect => {
try {
effect.dispose();
}
catch (error) {
this.reportError(error, 'dispose');
}
});
this._effectSet = undefined;
this.config.errorHandler = null;
return true;
}
return false;
}
/**
* 暂停作用域中的所有副作用
* 此操作会触发所有副作用的pause方法
*
* @returns {boolean} 操作结果,如果操作成功则返回true,否则返回false
* @override
*/
pause() {
if (super.pause()) {
this._effectSet?.forEach(effect => effect?.pause?.());
return true;
}
return false;
}
/**
* 恢复作用域中的所有副作用
* 此操作会触发所有副作用的resume方法
*
* @returns {boolean} 操作结果,如果操作成功则返回true,否则返回false
* @override
*/
resume() {
if (super.resume()) {
this._effectSet?.forEach(effect => effect.resume());
return true;
}
return false;
}
}
/**
* 作用域上下文标识符,用于在上下文中唯一标识作用域
*
* @public
* @static
* @readonly
*/
Object.defineProperty(EffectScope, "contextTag", {
enumerable: true,
configurable: true,
writable: true,
value: Symbol('EFFECT_SCOPE_CONTEXT_TAG')
});