✊不积跬步,无以至千里;不积小流,无以成江海。
实现发布订阅
以下是一个使用 JavaScript 实现发布-订阅模式的基本示例代码:
javascript
// 发布者
const publisher = {
subscribers: [],
// 添加订阅者
subscribe(callback) {
this.subscribers.push(callback);
},
// 取消订阅
unsubscribe(callback) {
this.subscribers = this.subscribers.filter(subscriber => subscriber !== callback);
},
// 发布消息
publish(data) {
this.subscribers.forEach(subscriber => subscriber(data));
}
};
// 订阅者1
function subscriber1(data) {
console.log('Subscriber 1:', data);
}
// 订阅者2
function subscriber2(data) {
console.log('Subscriber 2:', data);
}
// 订阅者3
function subscriber3(data) {
console.log('Subscriber 3:', data);
}
// 添加订阅者
publisher.subscribe(subscriber1);
publisher.subscribe(subscriber2);
publisher.subscribe(subscriber3);
// 发布消息
publisher.publish('Hello, World!');
// 取消订阅订阅者2
publisher.unsubscribe(subscriber2);
// 再次发布消息
publisher.publish('Goodbye!');
当我们运行上述代码时,它会执行以下操作:
- 创建一个
publisher
对象,它包含一个空数组subscribers
,用于存储订阅者函数。 - 定义了三个订阅者函数
subscriber1
、subscriber2
和subscriber3
,它们会在收到消息时执行相应的操作。 - 使用
publisher.subscribe
方法将订阅者函数添加到subscribers
数组中。我们添加了subscriber1
、subscriber2
和subscriber3
。 - 使用
publisher.publish
方法发布一条消息。这将触发publisher
对象中的所有订阅者函数执行相应的操作。在本例中,发布了一条消息'Hello, World!'
。 - 所有订阅者函数都被调用,并输出相应的消息。因此,我们会在控制台上看到类似以下的输出:
yaml
Subscriber 1: Hello, World!
Subscriber 2: Hello, World!
Subscriber 3: Hello, World!
- 使用
publisher.unsubscribe
方法取消订阅者2(即subscriber2
)。 - 使用
publisher.publish
方法再次发布一条消息。由于已取消订阅者2,只有订阅者1和订阅者3会收到消息。 - 在控制台上,我们会看到类似以下的输出:
yaml
Subscriber 1: Goodbye!
Subscriber 3: Goodbye!
代码中的 publisher
对象具有以下方法:
-
subscribe(callback)
: 这个方法用于添加订阅者函数到subscribers
数组中。订阅者函数是一个回调函数,当发布者发布消息时,这些订阅者函数将被调用。参数callback
是一个函数,表示要添加为订阅者的回调函数。例如,我们可以使用publisher.subscribe(subscriber1)
来将subscriber1
添加为订阅者。当调用subscribe
方法时,订阅者函数将被添加到publisher
对象的subscribers
数组中,以便在以后的消息发布中被调用。 -
unsubscribe(callback)
: 这个方法用于从subscribers
数组中取消订阅特定的订阅者函数。通过使用unsubscribe
方法,我们可以选择性地取消订阅某个订阅者函数,使其不再接收后续的发布消息。参数callback
是一个函数,表示要取消订阅的回调函数。例如,我们可以使用publisher.unsubscribe(subscriber2)
来取消订阅subscriber2
。当调用unsubscribe
方法时,它会遍历subscribers
数组,并使用filter
方法来移除与传入的回调函数匹配的订阅者函数。 -
publish(data)
: 这个方法用于发布消息,将消息传递给所有的订阅者函数。当发布者调用publish
方法时,所有订阅者函数将会被调用,并接收发布的消息作为参数。参数data
是要发布的消息数据。例如,我们可以使用publisher.publish('Hello, World!')
来发布一条消息。当调用publish
方法时,它会遍历subscribers
数组,并对每个订阅者函数调用该函数,并将消息作为参数传递给它们。这样,所有的订阅者函数都能够接收到发布的消息,并执行相应的操作
在示例中,我们添加了三个订阅者函数,并发布了一条消息。通过订阅和发布的机制,所有的订阅者函数都能够接收到发布的消息,并执行相应的操作。取消订阅者函数后,它将不再接收到后续的发布消息。
Promise介绍
Promise 是 JavaScript 中用于处理异步操作的一种机制。它是 ECMAScript 6 (ES6) 引入的一种对象,用于管理异步操作的状态和结果。Promise 可以更优雅地处理异步代码,并提供了一种可靠的方式来处理成功、失败和异步操作完成后的结果。
Promise 对象有三种状态:
- Pending(进行中): 初始状态,表示异步操作正在进行中,尚未完成。
- Fulfilled(已完成): 表示异步操作已成功完成。
- Rejected(已拒绝): 表示异步操作失败或被拒绝。
一个 Promise 对象的状态一旦改变,就不会再改变。
使用 Promise 的基本语法如下:
javascript
const myPromise = new Promise((resolve, reject) => {
// 异步操作
// 如果操作成功,调用 resolve(value)
// 如果操作失败,调用 reject(error)
});
myPromise
.then((value) => {
// 处理操作成功的结果
})
.catch((error) => {
// 处理操作失败的结果
});
在上述代码中,我们创建了一个 Promise 对象 myPromise
,并传入一个执行器函数(executor function)。执行器函数接收两个参数 resolve
和 reject
,分别是用于将 Promise 状态改变为 Fulfilled 和 Rejected 的函数。
在执行器函数中,我们执行异步操作,并根据操作的结果调用 resolve
或 reject
。如果操作成功,我们调用 resolve
函数,并传入成功的结果(value
);如果操作失败,我们调用 reject
函数,并传入失败的原因(error
)。
使用 .then()
方法,我们可以在 Promise 对象状态变为 Fulfilled 时处理操作成功的结果。通过 .catch()
方法,我们可以在 Promise 对象状态变为 Rejected 时处理操作失败的结果。
Promise 还提供了其他方法,如 .finally()
、.all()
、.race()
等,用于处理多个 Promise 对象的组合和并行操作。
使用 Promise 可以更好地管理异步代码,避免回调地狱(callback hell)的问题,使代码更加清晰、可读和可维护。它已成为现代 JavaScript 开发中处理异步操作的标准方式。
Promise API
Promise API 提供了一些方法来处理 Promise 对象的状态和结果。下面是一些常用的 Promise API:
Promise.resolve(value)
: 返回一个状态为 Fulfilled 的 Promise 对象,并将给定的value
作为成功的结果。Promise.reject(reason)
: 返回一个状态为 Rejected 的 Promise 对象,并将给定的reason
作为失败的原因。Promise.all(iterable)
: 接收一个可迭代对象(如数组)作为参数,返回一个新的 Promise 对象。该 Promise 对象在所有的 Promise 对象都变为 Fulfilled 状态时变为 Fulfilled,并将所有 Promise 对象的结果作为一个数组传递。Promise.race(iterable)
: 接收一个可迭代对象作为参数,返回一个新的 Promise 对象。该 Promise 对象在第一个变为 Fulfilled 或 Rejected 状态的 Promise 对象完成时变为相同的状态,并将第一个完成的 Promise 对象的结果传递。Promise.allSettled(iterable)
: 接收一个可迭代对象作为参数,返回一个新的 Promise 对象。该 Promise 对象在所有的 Promise 对象都变为 Fulfilled 或 Rejected 状态时变为 Fulfilled,并返回包含每个 Promise 对象状态和结果的对象数组。Promise.prototype.then(onFulfilled, onRejected)
: 在 Promise 对象的状态变为 Fulfilled 时调用onFulfilled
回调函数,在状态变为 Rejected 时调用onRejected
回调函数。该方法返回一个新的 Promise 对象,可以用于链式调用。Promise.prototype.catch(onRejected)
: 在 Promise 对象的状态变为 Rejected 时调用onRejected
回调函数。该方法返回一个新的 Promise 对象,用于处理 Promise 对象的错误。Promise.prototype.finally(onFinally)
: 在 Promise 对象的状态变为 Fulfilled 或 Rejected 时,无论如何都会调用onFinally
回调函数。该方法返回一个新的 Promise 对象,用于添加最终处理。
这些是 Promise API 的一些常见方法,用于处理 Promise 对象的状态、结果和错误。通过使用这些方法,我们可以更灵活地处理异步操作和多个 Promise 对象的组合。
Promise的实现
Promise 是 JavaScript 的内置对象,它的实现涉及到一些复杂的异步操作和状态管理。下面是一个简化版的 Promise 实现,用于演示其基本原理:
ini
class Promise {
constructor(executor) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback(this.value));
}
};
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback(this.reason));
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.status === 'fulfilled') {
setTimeout(() => {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.status === 'rejected') {
setTimeout(() => {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.status === 'pending') {
this.onFulfilledCallbacks.push((value) => {
setTimeout(() => {
try {
const result = onFulfilled(value);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push((reason) => {
setTimeout(() => {
try {
const result = onRejected(reason);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
-
首先,我们定义了一个名为
Promise
的类,它代表了一个 Promise 对象。 -
在构造函数中,我们初始化了 Promise 对象的初始状态为
'pending'
,并创建了用于存储结果和回调函数的变量。 -
resolve
和reject
是两个内部函数,用于将 Promise 对象的状态从'pending'
改变为'fulfilled'
或'rejected'
。它们接受一个参数,分别是成功的结果value
和失败的原因reason
。当状态改变时,它们会触发相应的成功或失败的回调函数。 -
在构造函数中,我们调用了
executor
函数,并传入resolve
和reject
函数作为参数。executor
函数是在创建 Promise 对象时传入的函数,它接受这两个参数,并用于执行异步操作。我们用try-catch
块包裹executor
函数的执行,以处理可能的异常。 -
then
方法用于注册成功和失败的回调函数,并返回一个新的 Promise 对象。它接受两个参数:onFulfilled
回调函数和onRejected
回调函数,分别用于处理成功和失败的情况。在then
方法内部,我们根据 Promise 对象的当前状态执行相应的回调函数。- 如果状态为
'fulfilled'
,我们使用setTimeout
来模拟异步操作,并在下一个事件循环中执行onFulfilled
回调函数。如果回调函数执行成功,则调用新的 Promise 对象的resolve
方法,传递成功的结果。 - 如果状态为
'rejected'
,我们使用setTimeout
来模拟异步操作,并在下一个事件循环中执行onRejected
回调函数。如果回调函数执行成功,则调用新的 Promise 对象的resolve
方法,传递成功的结果。 - 如果状态为
'pending'
,表示 Promise 对象的状态还未确定,我们将onFulfilled
和onRejected
回调函数分别放入onFulfilledCallbacks
和onRejectedCallbacks
数组中,以便在 Promise 对象状态确定后执行。
- 如果状态为
-
catch
方法是then
方法的一种特殊形式,用于注册处理失败的回调函数。它实际上是调用then
方法的简写形式,将第一个参数设置为null
。
这个简化版的 Promise 实现提供了基本的 Promise 功能,包括状态管理、回调函数注册、链式调用等。然而,真正的 Promise 实现要更复杂,涉及到更多的细节和错误处理机制。这个示例仅用于说明 Promise 的基本原理,实际使用中应使用原生的 JavaScript Promise 对象或符合 Promise/A+ 规范的第三方库。