返回
从0到1实现一个小型Comlink(仿Comlink)
前端
2023-09-30 20:07:02
简介
Comlink是一种强大的JavaScript API,允许在不同的窗口、工作线程或浏览器标签之间安全高效地进行跨域通信。它利用可信代理的概念,为我们提供了一种简便的方法来跨越不同源之间传输和调用函数。
构建Comlink
为了从头开始构建一个小型Comlink,我们需要创建一个称为代理 的对象,该对象将作为我们跨域通信的桥梁。该代理应具有以下方法:
- postMessage(): 将消息发送到另一端。
- onMessage(callback): 注册一个回调函数来处理传入的消息。
步骤 1:创建代理
class Proxy {
constructor() {
this.callbacks = [];
this.onmessage = null;
}
postMessage(message) {
if (this.onmessage) this.onmessage(message);
this.callbacks.forEach(cb => cb(message));
}
addEventListener(type, callback) {
if (type === 'message') this.callbacks.push(callback);
}
}
步骤 2:绑定代理
要将代理与其他窗口连接起来,我们需要将其绑定到一个函数。这将创建一个可以安全地在不同窗口之间传输的代理副本。
const proxy = new Proxy();
const boundProxy = proxy.bind(window);
步骤 3:在另一个窗口中创建接收器
在另一个窗口中,我们需要创建一个接收器来接收来自代理的消息。
const receiver = new Proxy();
receiver.onmessage = (message) => {
// 处理消息
};
receiver.addEventListener('message', boundProxy);
Q1:为什么在代理中返回一个fn,需要bind?
代理中返回一个函数是因为代理自身是一个可信代理,而可信代理可以在不同的窗口或线程之间安全地传递。bind()用于将代理绑定到一个特定对象,以便可以在其他窗口中使用该代理。
Q2:为什么等待一个代理会产生对then的一次拦截?
等待一个代理会产生对then的一次拦截,因为代理实际上是一个可信代理,可以作为promise来使用。then()拦截允许我们注册一个回调函数,当代理收到消息时该函数将被调用。
示例用法
我们的小型Comlink现在可以用于在不同的窗口之间传输和调用函数。例如,我们可以发送一个函数调用到另一个窗口,该函数将在接收窗口中执行。
// 在第一个窗口中
boundProxy.postMessage({
type: 'call',
functionName: 'greet',
args: ['Alice']
});
// 在第二个窗口中
receiver.onmessage = (message) => {
if (message.type === 'call') {
const result = window[message.functionName](...message.args);
boundProxy.postMessage({
type: 'return',
result
});
}
};
总结
通过创建一个小型的Comlink实现,我们深入了解了跨域通信的机制。Comlink在分布式系统和构建可扩展、弹性网络应用程序方面有着广泛的应用。从头开始构建Comlink有助于我们深入理解其底层原理,并能够定制和扩展其功能以满足特定的需求。