如何检查浏览器是否支持WebAssembly?

36

随着对WebAssembly的支持已经进入到所有主流浏览器中,我该如何检查当前访问我的网站的浏览器是否支持它?

3个回答

60

检测WebAssembly存在的几种方法。基本方法是检查全局范围内WebAssembly是否为类型"object",但在不同的JavaScript环境(主浏览器线程、工作线程、node.js)中访问“全局范围”可能会很棘手。

这样做从技术上来说也不足够,因为您可能具有WebAssembly支持,但由于CSP而无法编译或实例化(CSP禁止的内容尚未得到标准化,相关工作正在此处进行)。

保守的检查如下:

const supported = (() => {
    try {
        if (typeof WebAssembly === "object"
            && typeof WebAssembly.instantiate === "function") {
            const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
            if (module instanceof WebAssembly.Module)
                return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
        }
    } catch (e) {
    }
    return false;
})();

console.log(supported ? "WebAssembly is supported" : "WebAssembly is not supported");

以下是它的功能:

  • 检查当前范围内是否可以访问 WebAssembly。如果它不是全局的,那我们其实也不在乎!
  • 查看它是否有 .instantiate 函数,虽然在这里我们并没有使用它,但当你实际进行实例化时,你会想使用它,因为它是异步的,并且可以处理主线程或离线大模块。
  • 尝试同步编译最小可能的模块(魔术数字“\ 0”,“a”,“s”,“m”,后跟版本号1作为uint32编码),并查看我们是否得到了一个WebAssembly.Module
  • 最后,尝试同步实例化该模块,并检查它是否为WebAssembly.Instance

虽然有些复杂,但应该可以在以下情况下正常工作:

  • 代码运行的位置(主线程、worker、Node.js)。
  • CSP 最终如何被标准化。

快速进行了一次测试,这个测试只花费了1毫秒,用棒球棒也无法超越。 - Dexygen
@GeorgeJempty 我刚在JSBench上运行了它,在Safari上至少得到了20倍,在Chrome上得到了6倍。如果它在Web上真的成为瓶颈,浏览器会进行优化。 - JF Bastien
奇怪的是,来自this的HTML代码在Chromium 74.0.3729.169-2(在Arch Linux上)上没有显示不支持(红色),但在Firefox上显示不支持;而这个答案的代码则在两者上都显示不支持。我也发现奇怪的是,即使在Chromium上禁用了WebAssembly,在protonmail上仍然可以工作,我猜可能是通过:--disable-asm-webassembly --disable-features=AsmJsToWebAssembly --disable-features=WebAssembly,WebAssemblyStreaming没有被禁用。 - user11509478
这里获取的Hello world示例在Chromium 74.0.3729.169-2上也可以运行(但在Firefox上不行)。我猜WebAssembly在Chromium上不能被禁用了,但是在Firefox 69.0a1 (2019-05-26) (64-bit)上可以禁用。 - user11509478
好的,可以通过 --js-flags=--noexpose_wasm 禁用 Chromium WebAssembly,来源 - user11509478
虽然我同意这个答案是最健壮的方法,但由于我没有关注CSP或非浏览器上下文,我将其简化为function isWebAssemblySupported() { return (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function"); }; - Patrick Szalapski

3

(因声望不足无法评论,所以...) 如果你在旧版浏览器上进行测试,则不支持() =>语法,因此可以改为使用函数:

function wasmSupported() {
    // try/catch, return false; as in JF Bastien's answer
}
    
if(wasmSupported()) { ... }

1
但是,如果您在旧版浏览器上进行测试,WebAssembly肯定不受支持,对吗? - pacukluka
@pacukluka 我认为在大多数情况下,实际上if语句会与else语句一起使用,以便让最终用户知道网页出了什么问题。 - Ora Walters

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接