高级实现手写题
掌握 Promise 完整实现和事件发布订阅模式
7. Promise 完整实现
难度: ⭐⭐⭐ | 梯队: 进阶 | 标签: 状态机, 微任务
题目描述
实现一个符合 Promises/A+ 规范的 Promise。
代码实现
javascript
/**
* Promise 完整实现
*/
class MyPromise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor) {
this.status = MyPromise.PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
// 参数穿透
onFulfilled = typeof onFulfilled === 'function'
? onFulfilled
: (value) => value;
onRejected = typeof onRejected === 'function'
? onRejected
: (reason) => { throw reason; };
const promise2 = new MyPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
const rejectedMicrotask = () => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
if (this.status === MyPromise.FULFILLED) {
fulfilledMicrotask();
} else if (this.status === MyPromise.REJECTED) {
rejectedMicrotask();
} else {
this.onFulfilledCallbacks.push(fulfilledMicrotask);
this.onRejectedCallbacks.push(rejectedMicrotask);
}
});
return promise2;
}
/**
* 处理 then 返回值
*/
resolvePromise(promise2, x, resolve, reject) {
// 防止循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
let called = false;
try {
const then = x.then;
if (typeof then === 'function') {
then.call(
x,
(y) => {
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(x);
}
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(callback) {
return this.then(
(value) => MyPromise.resolve(callback()).then(() => value),
(reason) => MyPromise.resolve(callback()).then(() => { throw reason; })
);
}
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise((resolve) => resolve(value));
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
}示例调用
javascript
// 基础用法
new MyPromise((resolve) => {
resolve(1);
}).then((value) => {
console.log(value); // 1
return value + 1;
}).then((value) => {
console.log(value); // 2
});
// 边界条件:异步 resolve
new MyPromise((resolve) => {
setTimeout(() => resolve('async'), 100);
}).then((value) => {
console.log(value); // 'async'
});
// 边界条件:链式调用返回 Promise
new MyPromise((resolve) => {
resolve(1);
}).then((value) => {
return new MyPromise((r) => r(value * 2));
}).then((value) => {
console.log(value); // 2
});
// 边界条件:错误处理
new MyPromise((_, reject) => {
reject('error');
}).catch((reason) => {
console.log(reason); // 'error'
});
// 边界条件:then 中抛出错误
new MyPromise((resolve) => {
resolve(1);
}).then(() => {
throw new Error('oops');
}).catch((err) => {
console.log(err.message); // 'oops'
});
// 边界条件:finally
new MyPromise((resolve) => {
resolve(1);
}).finally(() => {
console.log('cleanup'); // 'cleanup'
}).then((value) => {
console.log(value); // 1
});复杂度分析
- 时间: O(1) 单次操作
- 空间: O(n) 回调队列
8. 事件发布订阅
难度: ⭐⭐ | 梯队: 第三梯队 | 标签: 设计模式, EventEmitter
题目描述
实现一个事件发布订阅系统,支持 on、off、emit、once 方法。
代码实现
javascript
/**
* EventEmitter 事件发布订阅
*/
class EventEmitter {
constructor() {
this.events = new Map();
}
/**
* 订阅事件
* @param {string} event - 事件名
* @param {Function} listener - 监听函数
* @return {EventEmitter}
*/
on(event, listener) {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event).push(listener);
return this;
}
/**
* 取消订阅
* @param {string} event - 事件名
* @param {Function} listener - 要移除的监听函数
* @return {EventEmitter}
*/
off(event, listener) {
if (!this.events.has(event)) return this;
if (!listener) {
// 没有指定 listener,移除该事件所有监听
this.events.delete(event);
} else {
const listeners = this.events.get(event);
const index = listeners.indexOf(listener);
if (index !== -1) {
listeners.splice(index, 1);
}
if (listeners.length === 0) {
this.events.delete(event);
}
}
return this;
}
/**
* 触发事件
* @param {string} event - 事件名
* @param {...any} args - 传递给监听函数的参数
* @return {boolean}
*/
emit(event, ...args) {
if (!this.events.has(event)) return false;
const listeners = this.events.get(event).slice(); // 复制防止修改
listeners.forEach((listener) => {
listener.apply(this, args);
});
return true;
}
/**
* 只订阅一次
* @param {string} event - 事件名
* @param {Function} listener - 监听函数
* @return {EventEmitter}
*/
once(event, listener) {
const wrapper = (...args) => {
listener.apply(this, args);
this.off(event, wrapper);
};
// 保存原始函数引用,方便 off 时匹配
wrapper.originalListener = listener;
this.on(event, wrapper);
return this;
}
/**
* 获取事件的监听器数量
*/
listenerCount(event) {
return this.events.has(event) ? this.events.get(event).length : 0;
}
/**
* 移除所有监听器
*/
removeAllListeners(event) {
if (event) {
this.events.delete(event);
} else {
this.events.clear();
}
return this;
}
}示例调用
javascript
const emitter = new EventEmitter();
// 基础用法:on 和 emit
const handler = (msg) => console.log(`Received: ${msg}`);
emitter.on('message', handler);
emitter.emit('message', 'Hello'); // 'Received: Hello'
// 多个监听器
emitter.on('message', (msg) => console.log(`Also got: ${msg}`));
emitter.emit('message', 'World');
// 'Received: World'
// 'Also got: World'
// off 移除监听器
emitter.off('message', handler);
emitter.emit('message', 'Test');
// 只输出 'Also got: Test'
// once 只执行一次
emitter.once('init', () => console.log('Initialized!'));
emitter.emit('init'); // 'Initialized!'
emitter.emit('init'); // 无输出
// 边界条件:emit 不存在的事件
console.log(emitter.emit('unknown')); // false
// 边界条件:off 不存在的事件
emitter.off('nonexistent'); // 不报错
// 边界条件:多参数
emitter.on('data', (a, b, c) => console.log(a, b, c));
emitter.emit('data', 1, 2, 3); // 1 2 3
// 边界条件:链式调用
new EventEmitter()
.on('a', () => console.log('a'))
.on('b', () => console.log('b'))
.emit('a')
.emit('b');
// 边界条件:listenerCount
const ee = new EventEmitter();
ee.on('test', () => {});
ee.on('test', () => {});
console.log(ee.listenerCount('test')); // 2
// 边界条件:removeAllListeners
ee.removeAllListeners('test');
console.log(ee.listenerCount('test')); // 0复杂度分析
- 时间:
- on/off: O(n) n 为该事件的监听器数
- emit: O(n)
- once: O(1)
- 空间: O(m × n),m 为事件数,n 为平均监听器数