MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

Loading and running WebAssembly code

현재 번역은 완벽하지 않습니다. 한국어로 문서 번역에 동참해주세요.

자바스크립트에서 웹어셈블리를 사용하기 위해서는, 먼저 컴파일/초기화 작업 이전에 웹어셈블리 모듈을 메모리 안으로 가져와야 합니다. 모듈들은 XMLHttpRequest 나 Fetch 를 이용하여 먼저 강타입의 배열로 초기화되어집니다. 아직은 이 두 개의 방법밖에 없지만 향후 더 개발 될 것입니다. 본 글에서는 웹어셈블리 바이트코드를 가져오는 각기 다른 방법에 대하여, 또한 컴파일 하는 방법, 초기화 하는 방법에 대한 레퍼런스를 제공할 것입니다. 

뭐가 문제인가요 ?

웹어셈블리는 아직 <script type='module'> 나 ES6 import 구문과 통합되지 않았기 때문에, 현재는 브라우저에서 내장되어 기본적으로 모듈을 가져올 수 있는 방법이 없습니다. 현재 가능한 유일한 방법은 당신의 웹어셈블리 모듈 바이너리를 포함하고 있는 ArrayBuffer 을 생성하여, WebAssembly.instantiate() 등의 메서드를 이용하여 컴파일하는 것 입니다. 이 방법은 생성자 함수인 new Function(string)을 사용하는 것과 유사하지만, 대신에 우리는 자바스크립트 소스 코드(문자열)을 웹어셈블리 소스코드(어레이 버퍼 바이트)로 치환하는 것이 다르죠.

그래서 어떻게 각각의 바이트들을 어레이 버퍼로 읽어 들인 후 컴파일 할 수 있을까요? 다음 장이 그 내용을 설명합니다.

Using Fetch

Fetch is a convenient, modern API for fetching network resources.

Let's say we have a WebAssembly module on the network called simple.wasm:

  • We can fetch it easily using the fetch() global function, which returns a promise that can resolve to a Response object.
  • We can convert the response into a typed array using the arrayBuffer() function, which returns a promise that resolves to the typed array.
  • Finally, we can compile and instantiate the typed array in one action using the WebAssembly.instantiate() function.

The necessary code block would look like this:

fetch('module.wasm').then(response =>
  response.arrayBuffer()
).then(bytes =>
  WebAssembly.instantiate(bytes, importObject)
).then(results => {
  // Do something with the compiled results!
});

Aside on instantiate() overloads

The WebAssembly.instantiate() function has two overload forms — the one shown above takes the byte code to compile as an argument and returns a promise that resolves to an object containing both the compiled module object, and an instantiated instance of it. The object looks like this:

{
  module : Module // The newly compiled WebAssembly.Module object,
  instance : Instance // A new WebAssembly.Instance of the module object
}

Note: Usually we only care about the instance, but it’s useful to have the module in case we want to cache it, share it with another worker or window via postMessage(), or simply create more instances.

Note: The second overload form takes a WebAssembly.Module object as an argument, and returns a promise directly containing the instance object as the result. See Second overload example.

Fetch and instantiate utility function

The above code pattern works, but it is somewhat long winded and laborious to write out every time, especially if you want to load multiple modules. To make it easier, we have created a utility function called fetchAndInstantiate(), which deals with this in the background by returning a single promise. You can find this function in wasm-utils.js, and it looks like this:

function fetchAndInstantiate(url, importObject) {
  return fetch(url).then(response =>
    response.arrayBuffer()
  ).then(bytes =>
    WebAssembly.instantiate(bytes, importObject)
  ).then(results =>
    results.instance
  );
}

After including this in your HTML, you can then fetch, instantiate, and access an instance of a WebAssembly module with one simple line:

fetchAndInstantiate('module.wasm', importObject).then(function(instance) {
  ...
})

Note: You can see many examples of this in action around our documentation (for example, see index.html) — this is the standard pattern we recommend for loading modules.

Running your WebAssembly code

Once you've got your WebAssembly instance available in your JavaScript, you can then start using features of it that have been exported via the WebAssembly.Instance.exports property. Your code might look something like this:

fetchAndInstantiate('myModule.wasm', importObject).then(function(instance) {
  // Call an exported function:
  instance.exports.exported_func();

  // or access the buffer contents of an exported memory:
  var i32 = new Uint32Array(instance.exports.memory.buffer);

  // or access the elements of an exported table:
  var table = instance.exports.table;
  console.log(table.get(0)());
})

Note: For more information on how exporting from a WebAssembly module works, have a read of Using the WebAssembly JavaScript API, and Understanding WebAssembly text format.

Using XMLHttpRequest

XMLHttpRequest is somewhat older than Fetch, but can still be happily used to get a typed array. Again, assuming our module is called simple.wasm:

  1. Create a new XMLHttpRequest() instance, and use its open() method to open a request, setting the request method to GET, and declaring the path to the file we want to fetch.
  2. The key part of this is to set the response type to 'arraybuffer' using the responseType property.
  3. Next, send the request using XMLHttpRequest.send().
  4. We then use the onload event handler to invoke a function when the response has finished downloading — in this function we get the array buffer from the response property, and then feed that into our WebAssembly.instantiate() method as we did with Fetch.

The final code looks like this:

request = new XMLHttpRequest();
request.open('GET', 'simple.wasm');
request.responseType = 'arraybuffer';
request.send();

request.onload = function() {
  var bytes = request.response;
  WebAssembly.instantiate(bytes, importObject).then(results => {
    results.instance.exports.exported_func();
  });
};

Note: You can an example of this in action in xhr-wasm.html.

문서 태그 및 공헌자

 이 페이지의 공헌자: kesuskim
 최종 변경: kesuskim,