HTML 结构
一个简单的 HTML 页面,其中包含一个按钮用于发起请求和一个按钮用于取消请求:
<button id="fetchButton">发起请求</button> <button id="cancelButton">取消请求</button> <div id="result"></div>
JavaScript 实现
在 JavaScript 中,我们将创建一个 AbortController
实例,并使用此实例的 signal
属性来控制 fetch
请求。
同时,我们还将实现一个按钮点击事件处理器,用于发起和取消请求。
// 获取 HTML 元素 const fetchButton = document.getElementById('fetchButton'); const cancelButton = document.getElementById('cancelButton'); const resultDiv = document.getElementById('result'); // 创建 AbortController 实例 const controller = new AbortController(); // 模拟一个长时间运行的请求 fetchButton.addEventListener('click', async () => { resultDiv.textContent = '正在加载...'; try { const response = await fetch('https://jsonplaceholder.typicode.com/todos/1', { signal: controller.signal }); const data = await response.json(); resultDiv.textContent = JSON.stringify(data); } catch (error) { if (error.name === 'AbortError') { resultDiv.textContent = '请求被取消'; } else { resultDiv.textContent = '发生错误'; } } }); // 取消请求 cancelButton.addEventListener('click', () => { controller.abort(); });
示例解释
在此示例中:
-
发起请求: 用户点击“发起请求”按钮时,会向一个 API 发送一个
fetch
请求。请求的控制信号来自于AbortController
实例。 -
取消请求: 如果用户在请求完成之前点击“取消请求”按钮,
AbortController
的abort
方法将被调用,正在进行的fetch
请求会被取消。 -
错误处理: 如果请求被取消,会捕获到一个
AbortError
,并相应地更新界面上的信息。
这个例子演示了命令模式在现代前端开发中的一个具体应用。通过将请求的控制逻辑(命令)封装在 AbortController
对象中,您可以方便地管理和取消异步 HTTP 请求。这种模式在处理复杂的用户界面交互和网络通信时尤为有用。
案例:简单的命令模式实现
假设我们有一个简单的文本编辑器应用,它可以执行撤销(undo)和重做(redo)操作。我们将使用命令模式来实现这些功能。
Step 1: 定义命令接口
首先,我们定义一个命令(Command)接口,它声明了执行命令的方法:
class Command { execute() {} undo() {} }
Step 2: 创建具体的命令
然后,我们创建具体的命令类来实现这个接口。例如,一个添加文本的命令:
class AddTextCommand extends Command { constructor(receiver, text) { super(); this.receiver = receiver; this.text = text; this.previousText = ''; } execute() { this.previousText = this.receiver.getText(); this.receiver.addText(this.text); } undo() { this.receiver.setText(this.previousText); } } class TextReceiver { constructor() { this.text = ''; } getText() { return this.text; } setText(text) { this.text = text; } addText(newText) { this.text += newText; } }
Step 3: 使用命令
最后,我们使用这些命令来操作文本编辑器:
// 文本编辑器实例 const editor = new TextReceiver(); // 创建命令 const addTextCommand = new AddTextCommand(editor, "Hello, Command Pattern!"); // 执行命令 addTextCommand.execute(); console.log(editor.getText()); // 输出: Hello, Command Pattern! // 撤销命令 addTextCommand.undo(); console.log(editor.getText()); // 输出: (空字符串)
Step 4: 命令调用者
通常,命令模式还包括一个调用者(Invoker)角色,它知道如何执行命令,但不知道命令的具体实现。在实际应用中,这可能是一个按钮或菜单项。
class Invoker { constructor() { this.history = []; } executeCommand(command) { this.history.push(command); command.execute(); } undo() { const command = this.history.pop(); if (command) { command.undo(); } } } // 使用 Invoker const invoker = new Invoker(); invoker.executeCommand(addTextCommand); invoker.undo();
总结
在这个示例中,我们创建了一个简单的文本编辑器,它使用命令模式来实现添加文本的操作以及撤销这些操作。Command
类定义了执行和撤销命令的接口,AddTextCommand
类实现了这些接口来具体操作文本。Invoker
类管理命令的执行和撤销,它代表了一个更高层次的操作,如用户界面的按钮或菜单。
这种模式使得命令的发送者和接收者解耦,提高了代码的灵活性和可扩展性。