首页 > 解决方案 > 获取 WebAssembly 实例化流式处理进度

问题描述

WebAssembly.instantiateStreaming是下载和实例化 .wasm 模块的最快方式,但是对于大型 .wasm 文件,它仍然需要很长时间。在这种情况下,仅显示微调器并不能提供足够的用户反馈。

有没有办法使用WebAssembly.instantiateStreamingapi 并获得某种形式的进度事件,以便可以向用户显示 eta?理想情况下,我希望能够显示百分比进度条/估计剩余时间指示器,以便用户知道他们需要等待多长时间。

标签: javascriptuser-experiencewebassembly

解决方案


在这里建立答案。

要获得WebAssembly.instantiateStreaming / WebAssembly.compileStreaming的进度,请使用自定义的 ReadableStream 创建一个新的 Fetch Response,它实现了它自己的控制器。

例子:

// Get your normal fetch response
var response = await fetch('https://www.example.com/example.wasm'); 

// Note - If you are compressing your .wasm file the Content-Length will be incorrect
// One workaround is to use a custom http header to manually specify the uncompressed size 
var contentLength = response.headers.get('Content-Length');

var total = parseInt(contentLength, 10);
var loaded = 0;

function progressHandler(bytesLoaded, totalBytes)
{
    // Do what you want with this info...
}

var res = new Response(new ReadableStream({
        async start(controller) {
            var reader = response.body.getReader();
            for (;;) {
                var {done, value} = await reader.read();

                if (done)
                {
                    progressHandler(total, total)
                    break
                }

                loaded += value.byteLength;
                progressHandler(loaded, total)
                controller.enqueue(value);
            }
            controller.close();
        },
    }, {
        "status" : response.status,
        "statusText" : response.statusText
    }));

// Make sure to copy the headers!
// Wasm is very picky with it's headers and it will fail to compile if they are not
// specified correctly.
for (var pair of response.headers.entries()) {
    res.headers.set(pair[0], pair[1]);
}

// The response (res) can now be passed to any of the streaming methods as normal
var promise = WebAssembly.instantiateStreaming(res)

推荐阅读