javascript基础学习系列三百一十七:跨上下文消息

本文介绍了跨文档消息(XDM)的概念,重点讲解了postMessage()方法在不同上下文中传递信息的安全机制,以及如何使用EncodingAPI进行字符串与定型数组的转换,强调了在处理长字符串和跨域通信中的最佳实践。
摘要由CSDN通过智能技术生成

跨文档消息,有时候也简称为 XDM(cross-document messaging),是一种在不同执行上下文(如不 同工作线程或不同源的页面)间传递信息的能力。例如,www.wrox.com 上的页面想要与包含在内嵌窗 格中的 p2p.wrox.com 上面的页面通信。在 XDM 之前,要以安全方式实现这种通信需要很多工作。XDM 以安全易用的方式规范化了这个功能。

XDM 的核心是 postMessage()方法。除了 XDM,这个方法名还在 HTML5 中很多地方用到过, 但目的都一样,都是把数据传送到另一个位置。
postMessage()方法接收 3 个参数:消息、表示目标接收源的字符串和可选的可传输对象的数组(只 与工作线程相关)。第二个参数对于安全非常重要,其可以限制浏览器交付数据的目标。下面来看一个 例子:

let iframeWindow = document.getElementById("myframe").contentWindow; iframeWindow.postMessage("A secret", "http://www.wrox.com");

最后一行代码尝试向内嵌窗格中发送一条消息,而且指定了源必须是"http://www.baidu.com"。 如果源匹配,那么消息将会交付到内嵌窗格;否则,postMessage()什么也不做。这个限制可以保护 信息不会因地址改变而泄露。如果不想限制接收目标,则可以给 postMessage()的第二个参数传"*", 但不推荐这么做。
接收到 XDM 消息后,window 对象上会触发 message 事件。这个事件是异步触发的,因此从消息 发出到接收到消息(接收窗口触发 message 事件)可能有延迟。传给 onmessage 事件处理程序的 event
注意 跨上下文消息用于窗口之间通信或工作线程之间通信。本节主要介绍使用 postMessage()与其他窗口通信 。关于工作线程之间通信、MessageChannel 和 BroadcastChannel,可以。

// 对数据进行一些处理
processMessage(event.data);
// 可选:向来源窗口发送一条消息 event.source.postMessage("Received!", "http://p2p.wrox.com");
} });

大多数情况下,event.source 是某个 window 对象的代理,而非实际的 window 对象。因此不能 通过它访问所有窗口下的信息。最好只使用 postMessage(),这个方法永远存在而且可以调用。
XDM 有一些怪异之处。首先,postMessage()的第一个参数的最初实现始终是一个字符串。后来, 第一个参数改为允许任何结构的数据传入,不过并非所有浏览器都实现了这个改变。为此,最好就是只 通过 postMessage()发送字符串。如果需要传递结构化数据,那么最好先对该数据调用 JSON.stringify(),通过 postMessage()传过去之后,再在 onmessage 事件处理程序中调用 JSON.parse()。
在通过内嵌窗格加载不同域时,使用 XDM 是非常方便的。这种方法在混搭(mashup)和社交应用 中非常常用。通过使用 XDM 与内嵌窗格中的网页通信,可以保证包含页面的安全。XDM 也可以用于 同源页面之间通信。

Encoding API

对象包含以下 3 方面重要信息。
 data:作为第一个参数传递给 postMessage()的字符串数据。
 origin:发送消息的文档源,例如"http://www.wrox.com"。
 source:发送消息的文档中 window 对象的代理。这个代理对象主要用于在发送上一条消息的
窗口中执行 postMessage()方法。如果发送窗口有相同的源,那么这个对象应该就是 window
对象。
接收消息之后验证发送窗口的源是非常重要的。与 postMessage()的第二个参数可以保证数据不
会意外传给未知页面一样,在 onmessage 事件处理程序中检查发送窗口的源可以保证数据来自正确的 地方。基本的使用方式如下所示:

window.addEventListener("message", (event) => { 18 // 确保来自预期发送者
if (event.origin == "http://www.wrox.com") {

Encoding API 主要用于实现字符串与定型数组之间的转换。规范新增了 4 个用于执行转换的全局类: 25

Encoding API

TextEncoder、TextEncoderStream、TextDecoder 和 TextDecoderStream。 注意 相比于批量(bulk)的编解码,对流(stream)编解码的支持很有限。
Encoding API 提供了两种将字符串转换为定型数组二进制格式的方法:批量编码和流编码。把字符 串转换为定型数组时,编码器始终使用 UTF-8。

1. 批量编码

所谓批量,指的是 JavaScript 引擎会同步编码整个字符串。对于非常长的字符串,可能会花较长时 间。批量编码是通过 TextEncoder 的实例完成的:

   const textEncoder = new TextEncoder();

这个实例上有一个 encode()方法,该方法接收一个字符串参数,并以 Uint8Array 格式返回每个 字符的 UTF-8 编码:

const textEncoder = new TextEncoder();
const decodedText = 'foo';
const encodedText = textEncoder.encode(decodedText);
// f 的 UTF-8 编码是 0x66(即十进制 102)
// o 的 UTF-8 编码是 0x6F(即二进制 111) console.log(encodedText); // Uint8Array(3) [102, 111, 111]

编码器是用于处理字符的,有些字符(如表情符号)在最终返回的数组中可能会占多个索引:

const textEncoder = new TextEncoder();
const decodedText = '☺';
const encodedText = textEncoder.encode(decodedText);
// ☺的UTF-8编码是0xF0 0x9F 0x98 0x8A(即十进制240、159、152、138) console.log(encodedText); // Uint8Array(4) [240, 159, 152, 138]

编码器实例还有一个 encodeInto()方法,该方法接收一个字符串和目标 Unit8Array,返回一个 字典,该字典包含 read 和 written 属性,分别表示成功从源字符串读取了多少字符和向目标数组写 入了多少字符。如果定型数组的空间不够,编码就会提前终止,返回的字典会体现这个结果:

const textEncoder = new TextEncoder();
const fooArr = new Uint8Array(3);
const barArr = new Uint8Array(2);
const fooResult = textEncoder.encodeInto('foo', fooArr); const barResult = textEncoder.encodeInto('bar', barArr);
console.log(fooArr); // Uint8Array(3) [102, 111, 111] console.log(fooResult); // { read: 3, written: 3 }
console.log(barArr); // Uint8Array(2) [98, 97] console.log(barResult); // { read: 2, written: 2 }

encode()要求分配一个新的 Unit8Array,encodeInto()则不需要。对于追求性能的应用,这个 差别可能会带来显著不同。

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值