class EventEmiter { constructor() { this.cache = [] } on(name, fn) { const tasks = this.cache[name] if (tasks) { tasks.push(fn) } else { this.cache[name] = [fn] } } off(name, fn) { if (!name) { this.cache = [] return } const tasks = this.cache[name] if (tasks) { if (!fn) { this.cache[name] = [] } const index = tasks.findIndex(item => item === fn) if (index >= 0) { tasks.splice(index, 1) } } } emit(name, ...args) { // 复制一份,防止回调里继续 on 导致死循环 const tasks = this.cache[name].slice() if (tasks) { for (let task of tasks) { task(...args) } } } once(name, cb) { const fn = (...args) => { cb(...args) this.off(name, fn) } this.on(name, fn) } }解释一下
时间: 2024-02-10 16:33:07 浏览: 21
这段代码实现了一个事件管理器类 EventEmiter,可以通过 on 方法订阅事件、通过 off 方法取消订阅事件、通过 emit 方法触发事件、以及通过 once 方法订阅一次性事件。
具体来说,EventEmiter 类有一个缓存对象 cache,用于存储不同事件对应的回调函数列表。on 方法用于订阅事件,它接受两个参数,name 表示事件名,fn 表示回调函数。当订阅一个已经存在的事件时,它会将回调函数添加到对应的回调函数列表中,否则会新建一个回调函数列表。off 方法用于取消订阅事件,它接受两个参数,name 表示事件名,fn 表示回调函数。当不传入任何参数时,它会清空所有事件的回调函数列表。当传入事件名时,它会删除该事件对应的回调函数列表,当传入事件名和回调函数时,它会删除该事件的对应的回调函数。emit 方法用于触发事件,它接受一个事件名和一些参数。它会从对应的回调函数列表中依次调用回调函数,并传入参数。once 方法用于订阅一次性事件,它接受两个参数,name 表示事件名,cb 表示回调函数。它会先定义一个新的回调函数 fn,它会在调用 cb 回调函数之后自动取消订阅该事件。然后调用 on 方法订阅事件,传入新的回调函数 fn。
相关问题
class EventEmiter { constructor() { this.cache = [] } on(name, fn) { const tasks = this.cache[name] if (tasks) { tasks.push(fn) } else { this.cache[name] = [fn] } } off(name, fn) { if (!name) { this.cache = [] return } const tasks = this.cache[name] if (tasks) { if (!fn) { this.cache[name] = [] } const index = tasks.findIndex(item => item === fn) if (index >= 0) { tasks.splice(index, 1) } } } emit(name, ...args) { const tasks = this.cache[name].slice() if (tasks) { for (let task of tasks) { task(...args) } } } once(name, cb) { const fn = (...args) => { cb(...args) this.off(name, fn) } this.on(name, fn) } }
这段代码是一个基本的事件触发器(EventEmitter)类,其主要功能是为事件绑定回调函数、解除绑定、触发事件以及为事件绑定一次性回调函数。下面是对该类中各个方法的详细解释:
- constructor(): 构造函数,初始化事件缓存数组cache。
- on(name, fn): 为事件name绑定回调函数fn,如果事件已经存在,则将回调函数加入到事件对应的缓存数组中,否则创建一个新的缓存数组并将回调函数加入其中。
- off(name, fn): 解除事件name对应的回调函数fn的绑定,如果name不存在,则清空所有事件,如果fn为空,则清空name对应的所有回调函数,否则从name对应的缓存数组中查找回调函数fn并将其从中删除。
- emit(name, ...args): 触发事件name,并将参数args传递给事件对应的回调函数,如果事件不存在则不执行。
- once(name, cb): 为事件name绑定一次性回调函数cb,该回调函数只会执行一次,并在执行后自动解除绑定。
该事件触发器类是一种常见的设计模式,用于实现事件驱动编程。通过该类,我们可以为各种事件绑定回调函数,从而实现事件的响应和处理。
// 下载器类 class Downloader { constructor(data, options) { this.data = data; this.options = options; this.item = null; this.onStart = null; this.onProgress = null; this.onCompleted = null; this.data.progress = 0; // 新增 progress 属性 this.data.status='pause';//true 表示 进度没有结束,继续下载 this.data.timeid=0; } start() { const win = BrowserWindow.getFocusedWindow(); this.options.onStarted = (item) => { this.item = item; this.data.status='process';//true 表示 进度没有结束,继续下载 this.onStart(); }; this.options.onTotalProgress=(progress)=>{ this.data.progress = progress.percent * 100; // 更新 progress 属性 this.onTotalProgress(progress); } this.options.onCompleted = () => { this.onCompleted(); }; download(win, this.data.dowloadLink, this.options); } pause() { if (this.item) { this.item.pause(); } } resume() { if (this.item) { this.item.resume(); } } cancel() { if (this.item) { this.item.cancel(); } } } 这是我说的类,里面有异步方法,怎么实现
你可以在异步方法执行完毕后,通过 Promise 或回调函数的方式通知外部代码。例如,在 onCompleted 回调函数中设置一个 Promise,然后在外部代码中等待这个 Promise 执行完毕,再执行下一步操作。类似下面这样:
```
class Downloader {
constructor(data, options) {
this.data = data;
this.options = options;
this.item = null;
this.onStart = null;
this.onProgress = null;
this.onCompleted = null;
this.data.progress = 0;
this.data.status = 'pause';
this.data.timeid = 0;
}
start() {
const win = BrowserWindow.getFocusedWindow();
this.options.onStarted = (item) => {
this.item = item;
this.data.status = 'process';
this.onStart();
};
this.options.onTotalProgress = (progress) => {
this.data.progress = progress.percent * 100;
this.onTotalProgress(progress);
};
this.options.onCompleted = () => {
this.onCompletedPromise.resolve(); // 执行 Promise
};
this.onCompletedPromise = {}; // 保存 Promise 对象
this.onCompletedPromise.promise = new Promise((resolve, reject) => {
this.onCompletedPromise.resolve = resolve;
this.onCompletedPromise.reject = reject;
});
download(win, this.data.dowloadLink, this.options);
}
async pause() {
if (this.item) {
await this.onCompletedPromise; // 等待 Promise 执行完毕
this.item.pause();
}
}
async resume() {
if (this.item) {
await this.onCompletedPromise; // 等待 Promise 执行完毕
this.item.resume();
}
}
async cancel() {
if (this.item) {
await this.onCompletedPromise; // 等待 Promise 执行完毕
this.item.cancel();
}
}
}
```
这样就能保证异步方法执行完毕后再执行外部代码了。