消息订阅与发布(Publish/Subscribe)是一种常见的消息传递模式,也称为观察者模式(Observer Pattern)或事件模型(Event Model)。
在该模式中,有两个重要的角色:发布者和订阅者。发布者负责产生消息,并将消息发布到一个或多个主题(Topic)上。订阅者可以订阅一个或多个主题,以接收他们感兴趣的消息。当一个主题上有新消息发布时,所有订阅该主题的订阅者将会收到这个消息。
这种模式的优势在于它能够将发布者和订阅者分离,使得它们之间不需要直接交互。这种松散耦合的设计使得系统更加灵活和可扩展,能够更容易地添加新的发布者和订阅者。同时,它也可以有效地降低系统中的耦合度和复杂性。
常见的消息订阅与发布的实现方式包括使用消息队列(Message Queue)、事件总线(Event Bus)等。这些实现方式都提供了一种可靠、可扩展、高效的消息传递机制,可以在大规模的分布式系统中使用。
PubSubJS是一个JavaScript库,用于实现发布/订阅模式的消息传递机制。它提供了一种简单的API,可以方便地实现发布/订阅模式,从而解耦代码和提高代码复用性。
PubSubJS的核心概念是消息通道(channel),消息通道是一个主题(topic),可以将一个或多个订阅者订阅到该主题上。消息通道是由字符串标识的,可以使用任意的字符串作为标识符。
PubSubJS提供了以下API:
其中,订阅者是一个回调函数,当有消息发布到该通道时,订阅者会被调用,同时将发布的消息作为参数传递给它。
以下是一个使用PubSubJS的示例代码:
javascriptCopy code
// 订阅一个通道
var subscription = PubSub.subscribe('myChannel', function(msg, data) {
console.log(msg, data);
});
// 向通道发布一个消息
PubSub.publish('myChannel', 'hello world');
// 取消订阅一个通道
PubSub.unsubscribe(subscription);
上述示例代码中,我们订阅了一个名为“myChannel”的通道,当有消息发布到该通道时,回调函数会被调用并打印出消息和数据。然后,我们发布了一个消息到该通道,并取消了订阅。
总的来说,PubSubJS是一个简单、轻量级的JavaScript库,可以方便地实现发布/订阅模式的消息传递机制,它可以帮助我们实现模块化、松耦合的代码。
我们之前github搜索案例,数据传递:
改进步骤:
我们把数据放入主要使用的主键List;
List组件订阅消息,回调函数更新我们的state数据;
Search组件请求后端,发布消息。
List组件修改代码1.3-1如下所示,其他不变:
state = {
githubUsers: [], // 初始化状态,github用户
isFirst: true, // 是否第一次打开页面
isLoadign: false, // 数据是否加载中
err: '', // 存储相关的错误信息
}
componentDidMount() {
PubSub.subscribe('github-user', (_, data)=> {
this.setState(data)
})
}
Search组件修改代码1.3-2如下所示:
search = () => {
// 获取用户输入
const {keyelement: {value: keyword}} = this
// console.log(keyword);
// 发送请求前通知List更新状态
PubSub.publish('github-user', {isFirst: false, isLoading: true})
// 发起网络请求
axios.get(`/api1/search/users?q=${keyword}`).then(
resp => {
// console.log('请求成功',resp.data);
const data = resp.data.items.map(item => {
return {id: item.id, avatar: item.avatar_url, homePage: item.html_url, username: item.login}
})
PubSub.publish('github-user', {isLoading: false, githubUsers: data})
},
error => {
// console.log('请求失败', err);
PubSub.publish('github-user', {isLoading: false, err: error.message})
}
)
}
在当前前后端分离的情况下,前端请求数据,浏览器原生支持的API有2种:
XmlHttpRequest (XHR) 和 Fetch 都是用来发送 HTTP 请求的浏览器原生 API,但是它们之间有以下几点不同:
总的来说,XHR 和 Fetch 都是可靠的浏览器原生 HTTP 请求 API,具有各自的优势和适用场景,开发者可以根据具体情况选择适合自己的 API 来发送 HTTP 请求。
相信原生XmlHttpRequest一定给使用过的小伙伴留下了“美好的”回忆,基于XmlHttpRequest开发繁琐,对其做了封装和功能增强的axios库应运而生。axios之前我们通过react脚手架集成和使用过,下面我们来练习下fetch的使用。
Search组件搜索代码2.2-1如下修改:
search = async () => {
// 获取用户输入
const { keyelement: { value: keyword } } = this
// console.log(keyword);
// 发送请求前通知List更新状态
PubSub.publish('github-user', { isFirst: false, isLoading: true })
// 发起网络请求
try {
const resp = await fetch(`/api1/search/users2?q=${keyword}`)
let data = await resp.json()
data = data.items.map(item => {
return { id: item.id, avatar: item.avatar_url, homePage: item.html_url, username: item.login }
})
PubSub.publish('github-user', {isLoading: false, githubUsers: data})
} catch (error) {
PubSub.publish('github-user', {isLoading: false, err: error.message})
}
}
之前使用axios可以做相应的优化,这里我们不在演示,有兴趣的可以自己试一下。
通过github案例,我们做如下总结。
设置状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么处理;
ES6:结构赋值+重命名
let obj = {a:{b:1}}
const {a} = obj // 传统结构赋值
const {a:{b}} = obj // 连续结构赋值
const {a:{b: newName}} = obj // 连续结构赋值+重命名
消息订阅与发布
fetch发送请求(关注分离的设计思想)
async fun() {
try {
const resp = await fetch('rul')
let data = await resp.json()
// 业务逻辑
} catch (error) {
// 异常处理
}
}
❓QQ:806797785
⭐️源代码仓库地址:https://github.com/gaogzhen/react-staging.git
参考:
[1]React视频教程[CP/OL].2020-12-15.p71-73.
[2]React官网[CP/OL].
[2]ChatGPT[CP/OL].