TextEncoder: encodeInto() 方法
TextEncoder.encodeInto()
方法接受要编码的字符串和一个目标 Uint8Array
用于存放生成的 UTF-8 编码文本,并返回一个指示编码进度的字典对象。这可能比旧的 encode()
方法更有效率——尤其是在目标缓冲区是 Wasm 堆的视图时。
语法
encodeInto(string, uint8Array)
参数
string
-
包含要编码文本的字符串。
uint8Array
-
一个
Uint8Array
对象实例,用于存放生成的 UTF-8 编码文本。
返回值
编码到特定位置
encodeInto()
始终将其输出放在数组的开头。但是,有时使输出从特定索引开始很有用。解决方案是 TypedArray.prototype.subarray()
const encoder = new TextEncoder();
function encodeIntoAtPosition(string, u8array, position) {
return encoder.encodeInto(
string,
position ? u8array.subarray(position | 0) : u8array,
);
}
const u8array = new Uint8Array(8);
encodeIntoAtPosition("hello", u8array, 2);
console.log(u8array.join()); // 0,0,104,101,108,108,111,0
缓冲区大小
要转换 JavaScript 字符串 s
,完全转换所需的输出空间永远不少于 s.length
字节,且不多于 s.length * 3
字节。字符串的 UTF-8 到 UTF-16 长度比率取决于您使用的语言。
- 对于主要使用 ASCII 字符的基本英文文本,比率接近 1。
- 对于使用 U+0080 到 U+07FF 之间字符的脚本(包括希腊语、西里尔语、希伯来语、阿拉伯语等)的文本,比率约为 2。
- 对于使用 U+0800 到 U+FFFF 之间字符的脚本(包括中文、日语、韩语等)的文本,比率约为 3。
- 整个脚本不太可能完全使用 非 BMP 字符(尽管确实存在)。这些字符通常是数学符号、表情符号、历史脚本等。这些字符的比率为 2,因为它们在 UTF-8 中占用 4 个字节,在 UTF-16 中占用 2 个字节。
如果预期输出分配(通常在 Wasm 堆中)是短暂的,则为输出分配 s.length * 3
字节是有意义的,在这种情况下,保证第一次转换尝试将转换整个字符串。
例如,如果您的文本主要是英文,则长文本不太可能超过 s.length * 2
字节。因此,更乐观的方法可能是分配 s.length * 2 + 5
字节,并在乐观预测错误的罕见情况下执行重新分配。
如果预期输出是长期存在的,则计算最小分配 roundUpToBucketSize(s.length)
、最大分配大小 s.length * 3
,并选择一个阈值 t
(作为内存使用量和速度之间的权衡),以便如果 roundUpToBucketSize(s.length) + t >= s.length * 3
,则为 s.length * 3
分配内存。否则,首先为 roundUpToBucketSize(s.length)
分配内存并进行转换。如果返回值字典中的 read
项目为 s.length
,则转换完成。否则,将目标缓冲区重新分配到 written + (s.length - read) * 3
,然后通过获取从索引 read
开始的 s
的子字符串和从索引 written
开始的目标缓冲区的子缓冲区来转换其余部分。
上面的 roundUpToBucketSize()
是一个向上舍入到分配器桶大小的函数。例如,如果已知您的 Wasm 分配器使用 2 的幂桶,则如果 roundUpToBucketSize()
的参数是 2 的幂,则应返回该参数,否则应返回下一个 2 的幂。如果 Wasm 分配器的行为未知,则 roundUpToBucketSize()
应为恒等函数。
如果分配器的行为未知,您可能希望执行最多两个重新分配步骤,并将第一个重新分配步骤将剩余未转换长度乘以 2 而不是 3。但是,在这种情况下,不实现通常将已写入缓冲区长度乘以 2 是有意义的,因为在这种情况下,如果发生第二次重新分配,与原始长度乘以 3 相比,它将始终过度分配。以上建议假设您不需要为零终止符分配空间。也就是说,在 Wasm 端,您使用的是 Rust 字符串或非零终止的 C++ 类。如果您使用的是 C++ std::string
,即使显示给您的逻辑长度,在计算向上舍入到分配器桶大小时也需要考虑额外的终止符字节。有关 C 字符串,请参阅下一节。
无零终止
如果输入字符串在输入中包含字符 U+0000,则 encodeInto()
将在输出中写入 0x00 字节。encodeInto()
不会在逻辑输出后写入 C 样式的 0x00 哨兵字节。
如果您的 Wasm 程序使用 C 字符串,则您有责任写入 0x00
哨兵,并且如果 JavaScript 字符串包含 U+0000
,则无法阻止您的 Wasm 程序看到逻辑上截断的字符串。观察
const encoder = new TextEncoder();
function encodeIntoWithSentinel(string, u8array, position) {
const stats = encoder.encodeInto(
string,
position ? u8array.subarray(position | 0) : u8array,
);
if (stats.written < u8array.length) u8array[stats.written] = 0; // append null if room
return stats;
}
示例
<p class="source">This is a sample paragraph.</p>
<p class="result"></p>
const sourcePara = document.querySelector(".source");
const resultPara = document.querySelector(".result");
const string = sourcePara.textContent;
const textEncoder = new TextEncoder();
const utf8 = new Uint8Array(string.length);
const encodedResults = textEncoder.encodeInto(string, utf8);
resultPara.textContent +=
`Bytes read: ${encodedResults.read}` +
` | Bytes written: ${encodedResults.written}` +
` | Encoded result: ${utf8}`;
规范
规范 |
---|
编码标准 # ref-for-dom-textencoder-encodeinto① |
浏览器兼容性
BCD 表格仅在浏览器中加载
另请参阅
- 它所属的
TextEncoder
接口。 TextEncoder.encode()