Rust를 WebAssembly로 컴파일하기 - 웹어셈블리

Rust를 WebAssembly로 컴파일하기
========================

여러분이 Rust 코드를 가지고 있다면 WebAssembly로 컴파일 할 수 있습니다. 이 튜토리얼은 Rust 프로젝트를 컴파일하여 기존 웹 애플리케이션에서 사용하기 위해 알아야 할 모든 것을 설명합니다.

Rust 및 WebAssembly 사용 사례
------------------------

Rust와 WebAssembly를 위한 두가지 주요 사용 사례가 있습니다.

* 어플리케이션 전체를 만드는것 - Rust기반 Web app 만들기
* 어플리케이션의 일부를 만드는것 - Rust를 기존에 존재하는 JavaScript frontend에서 사용하는것

당분간, Rust 팀은 후자의 경우에 초점을 맞출 것입니다.그래서 여기서는 두번째 내용에 대해 다루겠습니다. 첫번째 use-case는 `yew`와 같은 프로젝트를 한번 확인해보세요.

이 튜토리얼에서는 Rust의 npm 패키지를 빌드하는 도구인 `wasm-pack`을 사용하여 npm 패키지를 빌드합니다. 이 패키지에는 WebAssembly 및 JavaScript 코드만 포함되므로 패키지 사용자는 Rust를 설치할 필요가 없습니다. 심지어 WebAssembly에서 작성된 것임을 알지 못할 수도 있습니다.

Rust 환경 설치
----------

환경을 설치하기 위해 필요한 모든 단계를 수행해 봅시다.

### Rust 설치

Install Rust와 다음 설명에 따라 Rust를 설치합니다. "rustup"이라는 툴을 설치할건데 다양한 버전의 Rust를 관리할 수 있게 해줍니다. 기본적으로 최신 배포버전의 Rust가 설치됩니다. Rustup은 Rust 컴파일러인 `rustc` Rust의 표준 라이브러리 인 `rust-std`, Rust의 패키지 메니저 `cargo`및 `rust-docs` 등 유용한 문서를 설치합니다.

**참고:** 설치를 완료한 뒤 cargo의 `bin` 디렉토리가 시스템의 `PATH`에 등록되어 있어야 함에 주의하십시오. 보통은 자동으로 등록되지만, 터미널을 재시작해야 할 수도 있습니다.

### wasm-pack

패키지를 빌드하기 위해, `wasm-pack`이라는 추가적인 툴이 필요합니다. 이것을 통해 코드를 WebAssembly로 컴파일하고, `npm`에 적합한 패키징을 생성할 수 있습니다. 설치를 하려면 터미널에 다음 명령을 입력합니다.

```bash
    cargo install wasm-pack
```

### Node.js 설치와 npm 계정 생성

이 튜토리얼에서 우리는 npm 패키지를 생성할 것이므로 Node.js와 npm이 설치되어 있어야 합니다. 추가적으로, 우리는 npm에 패키지를 배포할 것이며 npm 계정 역시 필요합니다. 이것들은 모두 무료입니다. 당신은 *기술적으로는* 패키지를 배포할 필요가 없지만, 패키지를 사용하는 것이 더 쉬우므로 이 튜토리얼에서 수행한다고 가정합니다.

Node.js와 npm을 설치하려면 Get npm! 페이지를 열고 안내를 따라하시면 됩니다. 버전을 선택할 때, 원하는 것을 선택하면 됩니다. 이 튜토리얼은 버전과는 무관합니다.

npm 계정을 만드려면 npm 가입 페이지 에서 양식을 작성하시면 됩니다.

그 다음은, 명령줄에서 `npm adduser` 명령을 실행합니다.

```bash
    $ npm adduser
    Username: yournpmusername
    Password:
    Email: (this IS public) you@example.com
```

계정명과 패스워드, 그리고 이메일을 입력하세요. 제대로 작동했다면, 다음 출력을 볼 수 있습니다.

```bash
    Logged in as yournpmusername on https://registry.npmjs.org/.
```

만약 제대로 되지 않았다면, 문제 해결을 위해 npm에 문의를 해보세요.

WebAssembly npm 패키지 빌드하기
------------------------

설치가 다 되었으므로, Rust의 새 패키지를 만듭시다. 개인 프로젝트를 담는 디렉터리로 이동한 뒤, 다음 명령어를 입력합니다.

```bash
    $ cargo new --lib hello-wasm
         Created library `hello-wasm` project
```

이 명령어는 `hello-wasm`으로 이름지어진 하위 디렉터리에 새 라이브러리를 생성합니다.

```bash
    +-- Cargo.toml
    +-- src
        +-- lib.rs
```

첫번째로, `Cargo.toml`은 빌드를 위해 설정하는 파일입니다. Bundler에서 `Gemfile`이나 npm에서 `package.json`을 써보셨다면 꽤 익숙할 것입니다. Cargo는 이것들과 비슷한 방식으로 작동합니다.

다음은, Cargo가 `src/lib.rs`에 다음 Rust 코드를 생성했을 것입니다.

```bash
    #[cfg(test)]
    mod tests {
        #[test]
        fn it\_works() {
            assert_eq!(2 + 2, 4);
        }
    }
```

우리는 이 테스트 코드를 사용하지 않을 것이므로, 삭제해도 좋습니다.

### Rust로 무언가를 써보기

`src/lib.rs`에 다음 코드를 적어봅시다.

```rust
    use wasm\_bindgen::prelude::\*;

    #[wasm\_bindgen]
    extern {
        pub fn alert(s: &str);
    }

    #[wasm\_bindgen]
    pub fn greet(name: &str) {
        alert(&format!("Hello, {}!", name));
    }
```

이것은 우리의 Rust project의 내용으로, 세가지 주요 부분이 있습니다. 그들에 대해 차례대로 얘기해봅시다. 여기서는 고수준의 설명을 제공하고 일부 세부 사항에 대해서 설명합니다. Rust 언어에 대해 좀 더 배우고 싶으시면 The Rust Programming Language 에서 확인하시면 됩니다.

#### Rust와 JavaScript간의 통신을 위한 `wasm-bindgen` 사용

첫 부분은 다음과 같습니다.

```rust
    use wasm\_bindgen::prelude::\*;
```

Rust에서 라이브러리는 크레이트(crate)라고 합니다.

알 것 같나요? *Cargo(화물)* 는 배에 *crate(상자)* 들을 실어 나릅니다.

세번째 줄의 `use` 키워드는 라이브러리로부터 코드를 불러옵니다. 이 경우, 우리는 `wasm_bindgen::prelude` 모듈 내에 있는 모든 것을 불러오게 됩니다. 다음 섹션에서 이것들의 기능에 대해 다룰 것입니다.

다음 섹션으로 넘어가기 전에 `wasm-bindgen`에 대해 좀 더 얘기해야 합니다.

`wasm-pack`은 다른 도구인 `wasm-bindgen`을 사용해 JavaScript와 Rust의 타입들 사이에 다리를 제공합니다. 이는 JavaScript가 문자열을 통해 Rust의 API를 호출하거나, JavaScript의 예외를 포착하기 위해 Rust의 함수를 호출할 수 있습니다.

우리는 패키지에서 `wasm-bindgen`의 기능을 사용할 것입니다. 실은, 그것들은 다음 섹션에 있습니다.

#### Rust에서 JavaScript의 외부함수 호출

다음 부분은 이렇게 되어있을 것입니다.

```rust
    #[wasm\_bindgen]
    extern {
        pub fn alert(s: &str);
    }
```

`#[ ]` 안에 있는 것을 속성이라고 부르는데, 이것은 다음에 오는 구문을 수정합니다. 이 경우에, 그 구문은 `extern`이며, Rust에게 외부에 정의된 함수를 호출할 것임을 알립니다. 이 속성의 경우, "`wasm-bindgen`은 이 함수들을 어떻게 찾을 것인지 알고 있다"고 알리는 것입니다.

세번째 줄의 함수 시그니처는 Rust로 작성되어있습니다. `alert` 함수는 문자열 타입의 `s` 하나를 인자로서 받는다는 의미입니다.

짐작하셨듯이, 이것은 JavaScript에 의해 제공되는 `alert` 함수입니다. 다음 섹션에서 이 함수를 호출할 것입니다.

JavaScript 함수를 호출하고 싶을 때면 언제든지 이들을 파일에 추가할 수 있으며, `wasm-bindgen`이 당신을 위해 그 모든 것을 설정할 것입니다. 아직 모든 것이 지원되지는 않지만, 우리는 노력하고 있습니다. 빠진 것이 있다면, 버그를 제출해주십시오.

#### JavaScript가 호출할 수 있는 Rust 함수 작성

마지막 부분은 여기 있습니다.

```rust
    #[wasm\_bindgen]
    pub fn greet(name: &str) {
        alert(&format!("Hello, {}!", name));
    }
```

`#[wasm_bindgen]` 속성이 한번 더 나왔습니다. 이번엔 `extern` 구문이 수정되는 대신, `fn` 구문이 수정됩니다. 이것은 Rust 함수를 JavaScript에 의해 호출될 수 있도록 함을 의미하며, `extern` 과는 반대 기능이 됩니다. 이것은 우리가 필요로 하는 기능이 아니라, 우리가 세상에 제공하는 기능이 될 것입니다.

이 함수의 이름은 `greet`이며, (`&str` 이라고 쓰여진) 문자열 타입의 `name` 하나를 인자로 갖습니다. 이것은 우리가 위에 있는 `extern` 블록에서 요구한 `alert` 함수를 호출하여, 문자열을 연결하는 `format!` 매크로를 전달합니다.

`format!`매크로는 이 경우에 서식 문자열과 변수를 두개의 인자로 받습니다. 서식 문자열은 `"Hello, {}!"` 입니다. 이것은 두번째 인자의 변수를 표시할 `{}`를 담고 있습니다. 변수의 경우 함수의 인자로 전달받은 `name`을 전달하므로, 우리가 `greet("Steve")`를 호출하였다면 매크로는 `"Hello, Steve!"`를 반환할 것입니다.

이것은 `alert()`에 인자로 전달되므로, 이 함수를 호출한다면 우리는 브라우저의 경고창에서 "Hello, Steve!"를 볼 수 있을 것입니다.

라이브러리가 모두 작성되었으므로, 빌드를 해봅시다.

### 작성된 코드를 WebAssembly로 컴파일

컴파일이 올바르게 되려면, 먼저 `Cargo.toml`에서 설정을 해줘야 합니다. 파일을 열면, 다음과 같은 내용이 있을 것입니다.
```

    [package]
    name = "hello-wasm"
    version = "0.1.0"
    authors = ["Your Name <you@example.com>"]
    description = "A sample project with wasm-pack"
    license = "MIT/Apache-2.0"
    repository = "https://github.com/yourgithubusername/hello-wasm"
    edition = "2018"

    [lib]
    crate-type = ["cdylib"]

    [dependencies]
    wasm-bindgen = "0.2"
```

리포지토리 이름을 작성하고, `author` 필드를 `git`이 사용하는 것과 같게 설정해주세요.

추가해야 할 커다란 부분은 아래에 있습니다. `[lib]` 섹션은 패키지를 `cdylib` 형식으로 빌드할 것이라고 Rust에게 알리는데, 이 튜토리얼에선 그 의미가 무엇인지 다루지 않을 것입니다. 자세한 설명은 Cargo 와 Rust Linkage 문서를 참조하십시오.

마지막의 `[dependencies]` 섹션에서, Cargo에게 어떤 버전의 `wasm-bindgen`에 의존하고 있는지 알립니다. 이 경우, 버전 `0.2.z`는 어떤 것이든 사용할 수 있지만, `0.3.0`이상부터는 사용하지 않습니다.

### 패키지 빌드하기

모든 셋팅이 끝났으므로, 패키지를 빌드합시다. 터미널에 다음을 입력합니다.

```bash
    wasm-pack build --scope mynpmusername
```

이 명령어를 입력하면 많은 일이 일어납니다. (그리고 특히 `wasm-pack`을 처음 실행했을 때 처럼 많은 시간이 걸립니다.) 이에 대한 자세한 사항을 알고 싶으면, Mozilla Hacks의 블로그 포스트를 확인해보세요. 간단히 요약하자면, `wasm-pack build`는:

1. Rust 코드를 WebAssembly로 컴파일 합니다.
2. 그 WebAssembly 위에서 `wasm-bindgen`을 실행하여, WebAssembly를 npm이 이해할 수 있는 모듈로 감싸는 JavaScript 파일을 생성합니다.
3. `pkg` 디렉터리를 만들고 JavaScript 파일과 WebAssembly 코드를 그 안으로 옮깁니다.
4. `Cargo.toml` 을 읽고 동등한 `package.json`을 생성합니다.
5. `README.md` 가 있다면 패키지로 복사합니다.

빌드가 끝났다면, `pkg` 디렉터리에 npm 패키지가 생성될 것입니다.

#### 코드 사이즈에 대한 오류

생성된 WebAssembly 코드의 크기를 확인해보면, 몇백 킬로바이트가 될 것입니다. 우리는 Rust에게 코드의 크기를 최적화하라고 지시하지 않았으며, 만약 그렇게 지시한다면 크기가 *많이* 줄어들 것입니다. 이것은 이 튜토리얼에서 다루는 내용을 벗어나지만, 자세한 내용을 보려면 Shrinking .wasm Size에 대한 Rust WebAssembly Working Group의 문서를 참조하십시오.

### npm에 패키지 배포

npm에 우리의 새 패키지를 배포해봅시다.

```bash
    cd pkg
    npm publish --access=public
```

우리는 이제 Rust로 쓰여졌으나, WebAssembly로 컴파일된 npm 패키지를 갖고 있습니다. 이것은 JavaScript에 쓰일 수 있도록 준비되었으며, 다른 사용자들은 Rust를 설치할 필요가 없습니다. 왜냐하면 패키지에는 WebAssembly 코드만 포함되어있으며, Rust 소스는 없기 때문입니다.

웹상의 패키지 사용하기
------------

우리의 새 패키지를 사용하는 웹사이트를 빌드해봅시다. 많은 사람들이 여러가지 번들러 도구를 사용해 npm패키지를 사용하는데, 이 튜토리얼에선 이들 중 하나인 `webpack`을 사용할 것입니다. 이것은 조금 복잡하고, 현실적인 사용 사례를 보여줄 것입니다.

`pkg` 와 `hello-wasm` 디렉터리를 빠져나가서, 다음처럼 `site`라는 이름의 새 디렉터리를 만들고 진입합니다.

```bash
    cd ../..
    mkdir site
    cd site
```

`package.json` 이라는 이름의 새 파일을 만들어, 다음 코드를 작성합니다.

```json
{
  "scripts": {
    "serve": "webpack-dev-server"
  },
  "dependencies": {
    "@mynpmusername/hello-wasm": "^0.1.0"
  },
  "devDependencies": {
    "webpack": "^4.25.1",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.10"
  }
}
```

`dependencies` 섹션에서 `@` 뒤에 실제 npm 계정명을 넣어주세요.

그 다음은 Webpack을 설정해야 합니다. `webpack.config.js` 파일을 만든 뒤, 다음 코드를 작성합니다.

```js
const path = require("path");
module.exports = {
  entry: "./index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "index.js",
  },
  mode: "development",
};
```

그리고 HTML 파일도 필요합니다. `index.html`을 만들고, 다음 내용을 작성합니다.

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>hello-wasm example</title>
  </head>
  <body>
    <script src="./index.js"></script>
  </body>
</html>
```

마지막으로, HTML에서 참조되는 `index.js`를 만들어 다음 내용을 작성합니다.

```js
const js = import("./node\_modules/@yournpmusername/hello-wasm/hello\_wasm.js");
js.then((js) => {
  js.greet("WebAssembly");
});
```

npm 계정명을 한번 더 입력해야 합니다.

이것은 `node_modules` 폴더에 있는 새 모듈을 불러옵니다. 이것은 모범 사례로 여겨지진 않지만, 데모이므로 지금은 괜찮습니다. 모듈이 로드되었면, 모듈로부터 `greet` 함수를 호출하여 `"WebAssembly"` 를 문자열로서 전달합니다. 여기엔 특별한 것이 없지만, Rust 코드를 호출한 방법에 주목해주세요. JavaScript 코드가 알 수 있는 한, 이것은 그저 정상적인 모듈일 뿐입니다.

파일들을 모두 만들었으니, 한번 보도록 합시다.

```bash
npm install
npm run serve
```

이것은 간단한 웹 서버를 시작합니다. `http://localhost:8080` 을 열면 화면에 `Hello, WebAssembly!` 라고 쓰여진 alert box가 나타납니다. 우리는 성공적으로 JavaScript로부터 Rust를, Rust로부터 JavaScript를 호출하였습니다.

결론
--

이것이 튜토리얼의 끝입니다. 우리는 당신이 이것이 쓸모있다는 것을 알게 되었길 기대합니다.

여기에 많은 흥미로운 작업이 진행되고 있습니다. 이것을 좀 더 낫게 만들고 싶다면, the Rust Webassembly Working Group을 확인해보세요.


Converting WebAssembly text format to wasm - 웹어셈블리

Converting WebAssembly text format to wasm
==========================================

WebAssembly에는 S- expression 기반의 텍스트 표현, 텍스트 편집기, 브라우저 개발자 도구 등에서 노출되도록 고안된 중간 양식이 있습니다.이 기사에서는 어떻게 작동하는지, 텍스트 형식 파일을 `.wasm` 어셈블리 형식으로 변환할 수 있는 도구를 사용하는 방법에 대해 설명합니다.

**참고:** 텍스트 형식 파일은 대개 `.wat` 확장자로 저장됩니다. 때로는 `.wast`도 사용됩니다.이 파일은 변환 할 때 `.wast`으로 변환되지 않는 파일에 허용되는 추가 테스트 명령을 포함하는 파일을 가리 킵니다 - assertions 등

A first look at the text format
-------------------------------

이 간단한 예제를 보자 - 다음 프로그램은 `imports`라는 모듈에서 `imported_func`라는 함수를 가져오고 `exported_func`라는 함수를 내 보냅니다.

```js
    (module
      (func $i (import "imports" "imported\_func") (param i32))
      (func (export "exported\_func")
        i32.const 42
        call $i
      )
    )
```

WebAssembly 함수 `exported_func`는 Google 환경에서 사용하기 위해 내보내집니다 (예 : WebAssembly 모듈을 사용하는 웹 앱). 이 함수를 호출하면 `imported_func`라는 가져온 JavaScript 함수가 호출됩니다.이 함수는 매개 변수로 제공된 값 (42)으로 실행됩니다.

Converting the text .wat into a binary .wasm file
-------------------------------------------------

위의 `.wat` 텍스트 표현 예제를 `.wasm` 어셈블리 형식으로 변환 해 봅시다.

1. 시작하려면 `simple.wat` 라는 텍스트 파일 안에 위의 목록을 복사하십시오.
2. 이 텍스트 표현을 우리가 사용하기 전에 브라우저가 실제로 읽는 어셈블리 언어로 어셈블해야합니다. 이를 위해 wabt 도구를 사용할 수 있습니다.이 도구에는 WebAssembly의 텍스트 표현과 wasm을 변환하는 컴파일러가 포함되어 있으며 그 반대의 경우도 가능합니다. https://github.com/webassembly/wabt로 이동 -이 페이지의 지침에 따라 도구를 설정하십시오.
3. 일단 도구를 만들었 으면 시스템 `PATH`에 `/wabt/out/clang/Debug` 디렉토리를 추가하십시오.
4. 그런 다음, wat2wasm 프로그램을 실행하여 입력 파일의 경로와 `-o` 매개 변수 다음에 출력 파일의 경로를 전달하십시오.

```bash
wat2wasm simple.wat -o simple.wasm
```

wasm을 `.wasm` 어셈블리 코드가 들어있는 `simple.wasm` 파일로 변환합니다.

**참고:** wasm2wat 도구를 사용하여 어셈블리를 다시 텍스트 표현으로 변환 할 수도 있습니다. 예 : `wasm2wat simple.wasm -o text.wat`.

Viewing the assembly output
---------------------------

출력 파일은 어셈블리 기반이므로 일반 텍스트 편집기에서는 볼 수 없습니다. 그러나 wat2wasm 도구의 `-v` 옵션을 사용하여 볼 수 있습니다. 아래 코드를 실행해 보세요:

```bash
wat2wasm simple.wat -v
```

이렇게하면 다음과 같은 방법으로 터미널에 출력을 줄 수 있습니다.

![several strings of binary with textual descriptions beside them. For example: 0000008: 01 ; section code ](/ko/docs/WebAssembly/Text_format_to_Wasm/assembly-output.png)

See also
--------

* Understanding WebAssembly text format — 텍스트 형식 구문에 대한 자세한 설명.
* Compiling from C/C++ to WebAssembly — Binaryen / Emscripten과 같은 도구는 소스 코드를 wasm으로 컴파일하고 JavaScript 컨텍스트에서 모듈을 실행하는 데 필요한 API 코드를 만듭니다. 그들을 사용하는 방법에 대해 자세히 알아보십시오.
* Using the WebAssembly JavaScript API — WebAssembly API 코드가 작동하는 방식에 대해 자세히 알고 싶다면이 내용을 읽으십시오.
* Text format — WebAssembly GitHub repo에서 텍스트 형식에 대한 자세한 설명.
* wast-loader — 이 모든 것을 처리하는 WebPack 용 로더입니다.


C/C++ 모듈을 웹어셈블리로 컴파일하기 - 웹어셈블리

C/C++ 모듈을 웹어셈블리로 컴파일하기
======================

C/C++ 같은 언어로 새로운 모듈을 작성한 경우, Emscripten같은 도구를 이용해서 WebAssembly로 컴파일 할 수 있습니다. 작동원리를 살펴보겠습니다.

Emscripten 환경 준비하기
------------------

필요한 개발 환경을 설정해 봅시다.

### 필요한 사전 준비 사항

 Emscripten SDK를 설치하기 위해, 아래 설명을 참고하세요.
 https://kripken.github.io/emscripten-site/docs/getting\_started/downloads.html

예제 컴파일 하기
---------

환경설정이 완료되었다면, Emscripten로 C로 작성된 예제를 어떻게 컴파일하는지 살펴보겠습니다. Emscripten으로 컴파일하는 방법은 여러 가지가 있지만, 여기서는 주요 시나리오 두 가지만 다루도록 하겠습니다.

* wasm으로 컴파일 하고 코드를 실행하기 위해 HTML을 만듭니다. 그리고 wasm을 실행하기 위한 JavaScript "glue"코드를 추가합니다.
* wasm으로 컴파일하고 바로 JavaScript 코드를 만듭니다.

아래에서 자세히 보겠습니다.

### HTML와 JavaScript 만들기

이 방법은 브라우저에서 WebAssembly 코드를 실행하는 데 필요한 모든 것을 emscripten에서 생성하도록 하는 가장 간단한 방법입니다.

1. 먼저 컴파일 할 예제가 필요합니다. 다음 C 예제 코드를 복사하여 로컬 드라이브의 새 폴더에 `hello.c` 파일을 만듭니다.

```cpp
#include <stdio.h>

int main() {
    printf("Hello World\n");
    return 0;
}
```

2. Emscripten 컴파일 환경에 접속하는 데 사용한 terminal을 통ㅇ해 hello.c 파일과 동일한 폴더로 이동한 후 다음 명령을 실행하세요.

```bash
emcc hello.c -o hello.html
```

명령과 함께 전달된 옵션은 다음과 같습니다.

* `-o hello.html`
 : Emscripten이 코드를 실행할 HTML 페이지 (및 사용할 파일 이름)를 생성하고 Wasm 모듈과 JavaScript "접착제" 코드를 생성하여 Wasm을 컴파일하고 인스턴스화하도록 지정합니다. Wasm을 사용해 웹 환경에서 사용할 수 있도록 지정합니다.

이 때, 소스 폴더에는 아래 파일이 있어야 합니다.

* 바이너리 Wasm 모듈 코드 (`hello.wasm`)
* native c 함수와 Javascript/Wasm을 번역해주는 접착제 코드를 포함한 Javascript 파일 (`hello.js`)
* Wasm 코드를 로드, 컴파일 및 인스턴스화하고 브라우저에 출력을 표시하는 HTML 파일 (`hello.html`)
### 예제 실행하기

이제 WebAssembly를 지원하는 브라우저에서 `hello.html`을 로드해야합니다. Firefox 52, Chrome 57, Edge 57, Opera 44에서 기본적으로 활성화됩니다.

**참고:** 생성된 HTML 파일 (`hello.html`) 을 로컬 하드 드라이브(예: `file://your_path/hello.html`)에서 직접 열려고 하면 오류가 발생합니다(`Wasm의 동기, 비동기 가져오기가 모두 실패했습니다`라는 메시지가 표시됩니다). HTTP 서버(`http://`)로 HTML 파일을 실행해야 합니다. 로컬 테스팅 서버를 설정하는 방법을 참고하세요.

 모든 것이 계획대로 작동했다면, Emscripten 콘솔의 "Hello world" 출력이 웹 페이지와 브라우저의 JavaScript 콘솔에 나타나야 합니다. 축하합니다. WebAssembly로 C를 컴파일하고 브라우저에서 실행했습니다!

 ![image](/ko/docs/WebAssembly/C_to_Wasm/helloworld.png)

### 사용자 정의 HTML 템플릿 사용하기

때로는 사용자 정의 HTML 템플릿을 사용하고 싶을 수도 있습니다. 방법에 대해 알아보도록 하겠습니다.

1. 우선 다음 C 코드를 새로운 폴더의 `hello2.c`파일로 만듭니다.

```cpp
#include <stdio.h>

int main() {
    printf("Hello World\n");
    return 0;
}
```

2. emsdk 저장소에서 `shell_minimal.html` 파일을 검색하세오. 이전의 새 폴더에서 `html_template`이라는 하위 폴더로 복사하십시오.
3. Emscripten 컴파일러 환경 터미널 창에서 새 폴더로 이동 한 후 다음 명령을 실행합니다.

```bash
emcc -o hello2.html hello2.c -O3 --shell-file html_template/shell_minimal.html
```

이번 명령어의 옵션은 약간 다릅니다.
    * 컴파일러가 여전히 JavaScript 접착제 코드와 `.html`을 출력한다는 것을 의미하는 `-o hello2.html`을 지정했습니다.
    * 코드를 최적화하는 데 사용되는 `-O3`를 지정했습니다. Emcc에는 `-O0` (최적화 없음), `-O1`, `-O2`, `-Os`, `-Oz`, `-Og` 및 `-O3`을 포함해 다른 C 컴파일러와 마찬가지로 최적화 수준이 존재합니다. `-O3`는 릴리스 빌드에 적합한 설정입니다.
    * 또한 `--shell-file html_template/shell_minimal.html`을 지정했습니다.이 예제는 예제를 실행할 HTML을 만드는 데 사용할 HTML 템플릿의 경로를 제공합니다.
4. 예제를 실행해 봅니다. 위 명령어를 실행하면 `hello2.html`파일을 생성합니다. 생성된 Wasm을 로드하고 실행할 때 추가되는 접착제 코드가 있는 템플릿과 거의 동일한 내용을 갖습니다. 브라우저에서 열면 마지막 예제와 같은 결과를 볼 수 있습니다.

**참고:** `-o` 플래그에 HTML 파일 대신 .js 파일을 지정하여 전체 HTML이 아닌 JavaScript "접착제" 파일\* 만 출력하도록 지정할 수 있습니다(예, `emcc -o hello2.js hello2.c -O3`). 이 고급 방법으로, 사용자 정의 HTML을 처음부터 완전히 빌드 할 수 있습니다. 제공된 HTML 템플릿을 사용하는 것이 보통 더 쉽습니다.

Emscripten은 메모리 할당, 메모리 누수 및 기타 여러가지 문제를 처리하기 위해 다양한 JavaScript "접착제" 코드가 필요합니다.

### C 코드에서 사용자 정의 함수 호출

JavaScript에서 C 코드에 정의된 함수를 쓰고 싶은 경우 Emscripten `ccall()` 함수와 `EMSCRIPTEN_KEEPALIVE`(외부에서 사용가능한 함수 목록에 추가해주는 기능)을 통해 함수를 사용 할 수 있습니다(JavaScript로 컴파일 할 때 C/C++ 소스 코드의 함수가 사라지고 처리 할 함수가없는 이유는 무엇입니까?를 참조하세요). 어떻게 작동하는지 살펴 보겠습니다.

1. 시작하려면, 다음 코드를 새 폴더에 `hello3.c`로 저장하세요.

```cpp
#include <stdio.h>
#include <emscripten/emscripten.h>

int main() {
   printf("Hello World\n");
   return 0;
}

#ifdef \_\_cplusplus
#define EXTERN extern "C"
#else
#define EXTERN
#endif

EXTERN EMSCRIPTEN_KEEPALIVE void myFunction(int argc, char \*\* argv) {
   printf("MyFunction Called\n");
}
```

기본적으로, Emscripten에서 생성된 코드는 항상 `main()` 함수를 호출하고 다른 함수는 불필요한 코드로 제거됩니다. 함수 이름 앞에 `EMSCRIPTEN_KEEPALIVE`를 쓰면 제거되지 않습니다. `EMSCRIPTEN_KEEPALIVE`를 사용하려면 `emscripten.h` 라이브러리를 가져와야 합니다.

**참고:** `#ifdef` 블록을 포함하여 C++ 코드에 이 코드를 포함 시켜도 이 예제는 계속 작동합니다. C코드를 넣으면 C와 C++ name mangling 규칙으로 인해 문제가 생길 수 있지만, C++를 사용하는 경우 외부 C 함수를 사용하여 이 문제를 해결하면 됩니다.
2. 편리성을 위해 `{{{ SCRIPT }}}`가 포함된 `html_template/shell_minimal.html`을 이 새로운 폴더에 콘텐츠로 추가하십시오(개발환경에 넣고 개발하는 것이 편합니다).
3. 이제 컴파일 단계를 다시 실행해 봅시다. 최신 폴더 내부(Emscripten 컴파일러 환경 터미널 창 내부)에서 다음 명령으로 C 코드를 컴파일하십시오. `NO_EXIT_RUNTIME`으로 컴파일해야 합니다. `main()`이 종료될 때 런타임이 종료 및 컴파일된 코드를 호출하는 게 유효하지 않게 됩니다. 이 방법은 적절한 C 에뮬레이션에 필요합니다. 예를 들어, `atexit()` 함수가 호출되는지 확인하는 데 필요합니다.

```bash
emcc -o hello3.html hello3.c --shell-file html_template/shell_minimal.html -s NO\_EXIT\_RUNTIME=1 -s "EXPORTED\_RUNTIME\_METHODS=['ccall']"
```

4. 브라우저에서 예제를 다시 로드하면 이전과 동일한 내용을 볼 수 있습니다!
5. 이제 JavaScript에 있는 새로운 `myFunction()`함수를 실행해야 합니다. 먼저, 텍스트 편집기에서 hello3.html을 열어주세요.
6. 아래와 같이, `<script type='text/javascript'>` 태그 바로 위에 `<button>`을 추가합니다.

```html
<button id="mybutton">Run myFunction</button>
```

7. 이제 첫 번째 `<script>` 요소의 끝에 다음 코드를 추가합니다.

```js
document.getElementById("mybutton").addEventListener("click", () => {
  alert("check console");
  const result = Module.ccall(
    "myFunction", // name of C function
    null, // return type
    null, // argument types
    null, // arguments
  );
});
```

이 방법은 `ccall()`을 사용하여 내보낸 함수를 호출하는 방법을 보여줍니다.

같이 보기
-----

* emscripten.org
 : Emscripten과 다양한 옵션에 대해 자세히 알아보세요.
* ccall/cwrap을 사용하여 JavaScript에서 컴파일된 C 함수 호출
* JavaScript로 컴파일할 때 C/C++ 소스 코드의 함수가 사라지거나, 처리할 함수가 없다는 메시지가 나타나는 이유는 무엇인가요?
* Mozilla Research의 WebAssembly
* 기존 C 모듈을 WebAssembly로 컴파일


Understanding WebAssembly text format - 웹어셈블리

Understanding WebAssembly text format
=====================================

사람이 WebAssembly를 읽고 편집 할 수 있게하려면 wasm 이진 형식의 텍스트 표현이 있어야합니다. 이것은 텍스트 편집기, 브라우저 개발자 도구 등에서 노출되도록 고안된 중간 양식입니다.이 장에서는 원시 구문과 텍스트 형식이 나타내는 기본 바이트 코드와 관련하여 Text format이 작동하는 방식과 JavaScript에서 wasm을 나타내는 객체 래퍼에 대해 설명합니다.

**참고:** 여기서 다루는 내용은 여러분이 웹어셈블리를 JavaScript에 바로 불러오는 이전의 방법보다 훨씬 어렵습니다.(웹어셈블리를 JavaScript API에 사용하기 참고), 하지만 여기서 배우는 내용을 통해 웹어셈블리 모듈을 작성해보면, JavaScript 라이브러리의 성능을 향상시킬수 있는 방법을 찾거나, 직접 웹어셈블리 컴파일러를 작성하는데 도움이 될 것입니다.

S-expressions
-------------

WebAssembly에서 바이너리와 텍스트 사이에 기본적인 코드 교환 방식을 모듈이라 칭합니다. 텍스트 형식에서는, 모듈은 하나의 큰 S-expressions로 표현됩니다. S-expressions는 트리를 텍스트 형식으로 묘사하는 오래되고 쉬운 방법입니다. 모듈을 모듈의 구조와 코드로 표현되는 노드의 트리를 작성하기 위한 수단으로 생각하시면 됩니다. 추상적인 문법을 가진 개발 언어와는 다르게 웹어셈블리의 트리는 단순하면서 일반적으로 많이 사용하는 방식으로 구성되었습니다.

우선, S- expressions이 어떻게 보이는지 봅시다. 트리의 각 노드는 한 쌍의 괄호`( ... )` 안에 있습니다. 괄호 안의 첫 번째 레이블은 노드의 유형을 알려주고, 그 후에 속성 또는 하위 노드의 공백으로 구분 된 목록이 있습니다. 즉, WebAssembly S-expression을 의미합니다.

```rust
    (module (memory 1) (func))
```

모듈이라는 최상위 노드와 2개의 자식 노드를 가진 트리로 구성되었습니다. 그리고 "메모리" 노드에서는 1이라는 속성으로 "함수" 노드를 지칭하였습니다. 이제 이 표현식이 가지는 의미를 간단하게 알아보겠습니다.

### 간단한 모듈

가장 간단하고, 작동 가능한 wasm 모듈 작성을 시작합니다.

```rust
    (module)
```

이 모듈은 전체적으로 비어 있지만 올바르게 작동하는 모듈입니다.

만약 이 모듈을 바이너리로 전환하면,(웹어셈블리 텍스트 형식을 wasm으로 변환 참조), 우리는 8바이트짜리 모듈 헤더를 이진 형식으로 보게 될 것입니다.

```rust
    0000000: 0061 736d              ; WASM\_BINARY\_MAGIC
    0000004: 0d00 0000              ; WASM\_BINARY\_VERSION
```

### Adding functionality to your module

별로 흥미롭지 않은 모양이군요. 그렇다면 한번 실행 가능한 모듈을 작성해 보도록 하겠습니다.

webassembly 모듈의 모든 코드는 다음과 같은 의사 코드 구조를 갖는 함수로 구성되어있습니다.

```rust
    ( func <signature> <locals> <body> )
```

* **명칭**(**signature**)은 함수에서 (인자를)받고 (반환 값)반환하는 형식을 정의합니다.
* **지역인수**(**locals**)는 JavaScript의 변수 같지만, 명시적으로 형식을 정의합니다.
* **본문**(**body**)은 저수준 정의를 일렬로 나열한 목록입니다.

좀 다르게 보여도 다른 언어의 함수와 비슷합니다.

Signatures and parameters
-------------------------

Signatures는 반환 형식 선언 목록 뒤에 오는 매개 변수 형식 선언 시퀀스입니다. 여기서 주목할 것은

* `(result)`가 없으면 함수는 아무것도 반환하지 않습니다.
* 현재 단 하나의 반환 형식을 가질 수 있으나, 이후에 여러개를 반환할 수 있게 될 것입니다.

각 인자로 wasm은 현재 4가지의 형식을 지원합니다.

* `i32`: 32-bit integer
* `i64`: 64-bit integer
* `f32`: 32-bit float
* `f64`: 64-bit float

하나의 인자를 받기 위해 `(param i32)`라고 작성하고, 반환 값을 받기 위해 `(result i32)`라고 작성합니다. 아래에 2개의 32비트 정수를 받고 64비트 부동소수를 반환하는 바이너리 함수를 작성하였습니다.

```rust
    (func (param i32) (param i32) (result f64) ... )
```

signature 뒤에는 형식을 가진 locals를 나열합니다. `(local i32)`와 같이 씁니다. parameter는 기본적으로 locals에 속하며, 함수 호출 시 인자에 값을 전달받아 초기화 됩니다.

local와 parameter를 getting, setting 하기
-------------------------------------

지역인수와 함수인자는 함수 본문에서 `get_local` 명령문과 `set_local` 명령문을 통해 가져오거나 설정할 수 있습니다.

The `get_local`/`set_local` 명령문은 숫자로 이루어진 요소를 가져오거나 설정합니다. parameter가 선언 순서상 먼저 위치하며, 그다음 locals 순으로 되어 있습니다.

```rust
    (func (param i32) (param f32) (local f64)
      get_local 0
      get_local 1
      get_local 2)
```

본문 첫 줄에 `get_local 0` 명령어로 i32 매게변수를 받아내게 되며, `get_local 1` 명령어로 f32 매게변수를 받게 될 것입니다. 그리고 `get_local 2` 명렁어로 f64 지역변수를 받을 수 있습니다.

여기서 하나의 문제가 생겼군요. 숫자로 된 순서대로 받자니 좀 혼란스럽고 짜증날 수 있습니다. 그래서 텍스트로 명명된 매게변수, 지역변수, 그리고 다른 요소들을 간편하게 달러문자 (`$`) 로 시작하여 선언할 수 있습니다.

따라서 위에 작성한 함수 명칭을 아래와 같이 재구성할 수 있습니다.

```rust
    (func (param $p1 i32) (param $p2 f32) (local $loc f64) …)
```

이렇게 작성하면 `get_local 0` 대신 `get_local $p1` 처럼 표현할 수 있습니다. (참고로 여기서 사용된 $인자는 바이너리로 변환 시 다시 숫자로 바뀌게 됩니다.)

Stack machines
--------------

우리가 함수 본문을 작성하기 전에 한가지 얘기할 게 더 있습니다. 바로 **스택머신** (stack machines) 이죠. 브라우저가 효율적으로 컴파일할 때, wasm 실행부 안에는 스택 머신에 대한 규칙이 정의되어 있습니다. 간단하게 생각하면 모든 형식을 스택에 넣고, 특정한 `i32`/`i64`/`f32`/`f64` 값을 스택에서 빼거나 넣는 식입니다.

예를 들면, `get_local`은 지역변수 값을 스택에 푸시하도록 정의됩니다. 그리고 `i32.add` 명령어로 두 개의 `i32` 값을 빼낸 다음(암묵적으로 스택에 넣은 2 개의 값을 가져갑니다.), 이 둘의 합(2^32 형태)을 계산한 다음, 결과로 나온 i32 값을 다시 넣게 됩니다.

함수가 호출되면, 이 함수는 빈 스택으로 시작하여 함수가 실행되는 동안 스택이 서서히 채우고 끝나면 다시 비워 버립니다. 아래 함수를 실행해 봅시다.

```rust
    (func (param $p i32)
      get_local $p
      get_local $p
      i32.add)
```

여기선 스택이 `i32` 값 딱 하나만 존재합니다. 그리고 (`$p + $p`) 식을 `i32.add` 명령어로 합한 결과가 나오죠. 결국 함수가 가지는 최후의 스택은 반환되는 값 하나 뿐입니다.

웹어셈블리 내 스택 머신의 유효성 보증은 명확합니다. 만약 `(result f32)` 식을 정의하면, 스택은 반드시 끝에 단 하나의 `f32` 값만 남아야 합니다. 만약 결과 형식이 정의되어 있지 않다면, 스택은 비어 있어야 하죠.

첫번째 함수 본문
---------

전에 언급했듯이, 함수의 본문은 단순히 함수가 호출됐을 때 실행할 작업의 리스트입니다. 이전에 다루었던 것을 종합하면 아래와 같이 간단한 함수를 포함하는 모듈을 선언할 수 있습니다.

```rust
    (module
      (func (param $lhs i32) (param $rhs i32) (result i32)
        get_local $lhs
        get_local $rhs
        i32.add
      )
    )
```

이 함수는 2개의 매개변수를 갖고, 둘을 더하고, 그 결과를 반환합니다.

함수의 본문에 넣을 수 있는 것들은 훨씬 많지만 지금은 간단하게 시작할겁니다. 당신은 앞으로 더 많은 예제들을 보게 될 것입니다. 사용 가능한 opcodes의 모든 목록을 보고싶다면 webassembly.org 시맨틱 문서에서 확인하세요.

### 함수 호출하기

함수는 혼자서 동작하지 않습니다. 호출해야합니다. ES2015 모듈에서와 마찬가지로 wasm 함수는 모듈 내부의 `export` 명령문에 의해 명시적으로 내보내야합니다.

locals와 마찬가지로 함수는 기본적으로 인덱스로 식별되지만 편의상 이름을 지정할 수 있습니다. 먼저 `func` 키워드 바로 뒤에 달러 기호가 붙은 이름을 추가합니다.

```rust
    (func $add … )
```

이제 내보내기 선언을 추가해야합니다. 다음과 같습니다.

```rust
    (export "add" (func $add))
```

여기서 `add`는 자바 스크립트에서 함수가 식별되는 이름이며 `$add`는 모듈 내에서 어떤 WebAssembly 함수가 내보내지는지를 선택합니다.

그래서 우리의 마지막 모듈은 (지금은) 다음과 같습니다.

```rust
    (module
      (func $add (param $lhs i32) (param $rhs i32) (result i32)
        get_local $lhs
        get_local $rhs
        i32.add)
      (export "add" (func $add))
    )
```

예제를 따라하려면 위의 모듈을 `add.wat`라는 파일에 저장 한 다음 wabt를 사용하여 `add.wasm`이라는 이진 파일로 변환하십시오 (자세한 내용은 Converting WebAssembly text format to wasm 참조).

다음으로 바이너리를 `addCode` (Fetching WebAssembly Bytecode (en-US)에서 설명한대로)라는 형식화 된 배열에로드하고, 컴파일 및 인스턴스화 한 다음 자바 스크립트에서 `add` 함수를 실행합니다. (이제 `add()`는 인스턴스의 `exports` (en-US) 속성에서 찾을 수 있습니다)

```js
WebAssembly.instantiateStreaming(fetch("add.wasm")).then((obj) => {
  console.log(obj.instance.exports.add(1, 2)); // "3"
});
```

**참고:** 이 예제는 GitHub에서 add.html로 찾을 수 있습니다 (see it live also). 인스턴스 함수에 대한 자세한 내용은 `WebAssembly.instantiate ()`를 참조하십시오.

기본 사항 둘러보기
----------

이제는 기본 사항을 다뤘습니다. 더 많은 고급 기능을 살펴 보겠습니다.

### 같은 모듈 내에 있는 다른 함수 호출하기

`call` 명령어는 인덱스 또는 이름이 지정된 단일 함수를 호출합니다. 예를 들어, 다음 모듈에는 두 개의 함수가 있습니다. 하나는 값 42를 반환하고, 다른 하나는 첫 번째 플러스 1을 호출 한 결과를 반환합니다.

```js
    (module
      (func $getAnswer (result i32)
        i32.const 42)
      (func (export "getAnswerPlus1") (result i32)
        call $getAnswer
        i32.const 1
        i32.add))
```

**참고:** `i32.const`는 단지 32 비트 정수를 정의하고 그것을 스택에 푸시합니다. 사용할 수있는 다른 유형의 `i32`를 바꿀 수 있으며 원하는 값으로 const 값을 변경할 수 있습니다 (여기서는 값을 `42`로 설정했습니다).

In this example you'll notice an `(export "getAnswerPlus1")` section, declared just after the `func` statement in the second function — this is a shorthand way of declaring that we want to export this function, and defining the name we want to export it as.

이는 함수 밖에서, 예전과 같은 방식으로 모듈의 다른 곳에서 별도의 function 문을 포함하는 것과 기능적으로 동일합니다. 예 :

```js
    (export "getAnswerPlus1" (func $functionName))
```

위의 모듈을 호출하는 JavaScript 코드는 다음과 같습니다.

```js
WebAssembly.instantiateStreaming(fetch("call.wasm")).then((obj) => {
  console.log(obj.instance.exports.getAnswerPlus1()); // "43"
});
```

**참고:** 이 예제는 GitHub에서 call.html로 찾을 수 있습니다 (see it live also).

### JavaScript에 함수 가져오기

우리는 이미 JavaScript에서 WebAssembly 함수를 호출하는 것을 보았습니다. 그러나 JavaScript 함수를 호출하는 WebAssembly는 어떻습니까? WebAssembly에는 실제로 JavaScript에 대한 기본 지식이 없지만 JavaScript 또는 Wasm 함수를 사용할 수있는 함수를 가져 오는 일반적인 방법이 있습니다. 예제를 살펴 보겠습니다.

```js
    (module
      (import "console" "log" (func $log (param i32)))
      (func (export "logIt")
        i32.const 13
        call $log))
```

WebAssembly에는 2 단계 네임 스페이스가 있으므로 여기서 import 문은 콘솔`console`모듈에서 `log` 함수를 가져 오기를 요청한다는 의미입니다. 또한 앞서 소개 한 `call` 명령어를 사용하여 내 보낸 `logIt` 함수가 가져온 함수를 호출하는지 확인할 수 있습니다.

가져온 함수는 일반적인 함수와 같습니다. WebAssembly 유효성 검사에서 정적으로 서명하는 시그니처가 있으며, 인덱스가 주어지며 이름을 지정하고 호출 할 수 있습니다.

JavaScript 함수에는 서명 개념이 없으므로 임포트의 선언 된 서명에 관계없이 모든 JavaScript 함수를 전달할 수 있습니다. 모듈이 가져 오기를 선언하면 `WebAssembly.instantiate()`의 호출자는 해당 속성이있는 가져 오기 객체를 전달해야합니다.

위의 경우 `importObject.console.log`가 JavaScript 함수 인 객체 (`importObject`라고 부름)가 필요합니다.

이것은 다음과 같습니다.

```js
var importObject = {
  console: {
    log: function (arg) {
      console.log(arg);
    },
  },
};

WebAssembly.instantiateStreaming(fetch("logger.wasm"), importObject).then(
  (obj) => {
    obj.instance.exports.logIt();
  },
);
```

**참고:** 이 예제는 GitHub에서 logger.html로 찾을 수 있습니다 (라이브(see it live also)도 참조하십시오).

### Declaring globals in WebAssembly

WebAssembly는 하나 이상의 `WebAssembly.Module` 인스턴스 전체에서 JavaScript 및 가져오기 / 내보내기가 가능한 전역 변수 인스턴스를 생성 할 수 있습니다. 이는 여러 모듈을 동적으로 연결할 수 있으므로 매우 유용합니다.

WebAssembly 텍스트 형식에서는 다음과 비슷합니다 (GitHub의 global.wat 참조, 라이브 JavaScript 예제는 global.html 참조).

```js
    (module
       (global $g (import "js" "global") (mut i32))
       (func (export "getGlobal") (result i32)
            (get_global $g))
       (func (export "incGlobal")
            (set_global $g
                (i32.add (get_global $g) (i32.const 1))))
    )
```

이것은 `global` 키워드를 사용하여 전역 값을 지정한다는 점을 제외하고는 이전에 보았던 것과 비슷하게 보이며 변수 mutable을 원하면 값의 데이터 유형과 함께 `mut` 키워드를 지정합니다.

JavaScript를 사용하여 동일한 값을 만들려면 `WebAssembly.Global()` 생성자를 사용합니다.

```js
const global = new WebAssembly.Global({ value: "i32", mutable: true }, 0);
```

### WebAssembly Memory

위의 예로든 로깅 기능은 아주 끔찍합니다. 단 하나의 정수만 출력합니다!(이 정수가 뭔지 어떻게 알겠어요 그죠?) 텍스트 문자열을 기록하려면 어떻게 해야할까요. 문자열 및 기타 복잡한 데이터 유형을 처리하기 위해 WebAssembly는 메모리를 제공합니다. 메모리는 사용하면서 크기를 키울 수 있는 대량의 바이트 배열 입니다. WebAssembly에는 linear memory에서 읽고 쓰는 데 필요한 `i32.load` 및 `i32.store`와 같은 지침이 들어 있습니다.

JavaScript의 관점에서 볼 때 크기가 조정 가능한 큰 `ArrayBuffer` 안에 메모리가 모두있는 것처럼 보입니다. 이는 말 그대로 asm.js와 함께 사용해야함을 의미합니다. (크기 조정할 수 없다는 점을 제외하고요. asm.js Programming model을 참고 하세요.).

따라서 문자열은 이 선형 메모리 내부의 있는 sequence of bytes라고 할 수 있습니다. 우리가 적절한 바이트 문자열을 메모리에 썼다고 가정 해 보고 어떻게 그 문자열을 JavaScript로 전달하는지 보겠습니다.

핵심은 자바 스크립트가 `WebAssembly.Memory()` 인터페이스를 통해 WebAssembly 선형 메모리 인스턴스를 생성하고 연관된 인스턴스를 사용하여 기존 메모리 인스턴스에 액세스 할 수 있다는 것입니다 (현재 모듈 인스턴스 당 하나만 가질 수 있음). 메모리 인스턴스에는 `buffer` (en-US) getter가 있습니다.이 buffer getter는 전체 선형 메모리를 가리키는 `ArrayBuffer`를 반환합니다.

예를 들어 JavaScript의 `Memory.grow()` (en-US) 메소드를 통해 메모리 인스턴스를 늘릴 수도 있습니다. grow가 발생하면 `ArrayBuffer`s는 크기를 변경할 수 없기 때문에 현재의 `ArrayBuffer`가 분리되고 더 큰 새 메모리를 가리 키도록 새 `ArrayBuffer`가 만들어집니다. 즉, JavaScript에 문자열을 전달하기 위해 수행해야하는 모든 작업은 길이를 나타내는 방법과 함께 선형 메모리에있는 문자열의 오프셋을 전달하는 것입니다.

문자열 자체의 길이를 인코딩하는 방법에는 여러 가지가 있습니다 (예 : C 문자열). 여기서 간단히하기 위해 offset과 length를 매개 변수로 전달합니다.

```js
    (import "console" "log" (func $log (param i32) (param i32)))
```

자바 스크립트 측면에서 우리는 TextDecoder API (en-US)를 사용하여 바이트를 자바 스크립트 문자열로 쉽게 디코딩 할 수 있습니다. (여기서는 `utf8`을 지정하지만 다른 많은 인코딩이 지원됩니다.)

```js
function consoleLogString(offset, length) {
  var bytes = new Uint8Array(memory.buffer, offset, length);
  var string = new TextDecoder("utf8").decode(bytes);
  console.log(string);
}
```

이제 남은 부분은 `consoleLogString`이 WebAssembly `memory`에 액세스하는 부분입니다. WebAssembly는 JavaScript로 `Memory` 객체를 만들고 WebAssembly 모듈에서 메모리를 가져 오거나 WebAssembly 모듈에서 메모리를 만들어 JavaScript로 내보낼 수 있는 유연성을 제공합니다.

간단히하기 위해 JavaScript로 작성한 다음 WebAssembly로 가져와 봅시다. 우리의 `import`statement는 다음과 같이 작성됩니다 :

```rust
    (import "js" "mem" (memory 1))
```

`1`은 가져온 메모리에 최소 1 페이지의 메모리가 있어야 함을 나타냅니다 (WebAssembly에서 페이지를 64KB로 정의 함).

문자열 "Hi"를 인쇄하는 완전한 모듈을 보겠습니다. 일반적인 컴파일 된 C 프로그램에서는 함수를 호출하여 문자열에 대한 메모리를 할당하지만 여기에 자체 어셈블리를 작성하고 전체 선형 메모리를 소유하기 때문에 `data` 섹션을 사용하여 전역 메모리에 문자열 내용을 쓸 수 있습니다. 데이터 섹션은 바이트의 문자열이 인스턴스화 시간에 주어진 오프셋에 쓰여질 수 있도록 하며 원시 실행 가능 형식의 `.data`sections와 유사합니다.

최종 wasm 모듈을 확인하겠습니다.

```rust
    (module
      (import "console" "log" (func $log (param i32 i32)))
      (import "js" "mem" (memory 1))
      (data (i32.const 0) "Hi")
      (func (export "writeHi")
        i32.const 0  ;; pass offset 0 to log
        i32.const 2  ;; pass length 2 to log
        call $log))
```

**참고:** 위와 같이 WebAssembly 파일의 주석을 허용하는 두 개의 세미콜론 구문 (`;;`)을 확인하십시오.

자바 스크립트에서 우리는 1 페이지 메모리를 만들고 그것을 전달할 수 있습니다. 결과적으로 "Hi"가 콘솔에 출력됩니다 :

```js
var memory = new WebAssembly.Memory({ initial: 1 });

var importObject = { console: { log: consoleLogString }, js: { mem: memory } };

WebAssembly.instantiateStreaming(fetch("logger2.wasm"), importObject).then(
  (obj) => {
    obj.instance.exports.writeHi();
  },
);
```

**참고:** 깃허브에서 소스 전체버전을 확인할 수 있습니다. logger2.html (also see it live).

### WebAssembly tables

WebAssembly 텍스트 형식 둘러보기를 마무리하려면 WebAssembly에서 가장 복잡하고 어려운 부분 인 **tables**을 살펴 보겠습니다. 테이블은 기본적으로 WebAssembly 코드의 인덱스를 통해 액세스 할 수 있는 크기 조정이 가능한 참조 배열입니다.

왜 테이블이 필요한지를 알기 위해서는 앞서 보았던 `call` 명령어 (Calling functions from other functions in the same module 참고)가 필요합니다. 이 명령어는 정적 함수 인덱스를 취하며 따라서 오직 하나의 함수를 호출합니다. 그러나 호출 수신자가 런타임 값인 경우에는 어떻게 해야할까요?

* 자바 스크립트에서 항상 볼 수 있습니다. 함수는 최상위 클래스 입니다.
* C/C++에서, function pointers와 함께 볼 수 있습니다.
* C++에서, virtual functions와 함께 볼 수 있습니다.

WebAssembly에는 이를 구현하기 위해 일종의 호출 명령어가 필요했기 때문에 동적 함수 피연산자를 사용하는 `call_indirect`를 구현했습니다. 문제는 WebAssembly에서 피연산자를 지정해야하는 유일한 유형은 (현재) `i32`/`i64`/`f32`/`f64`라는 것입니다.

WebAssembly는 `anyfunc` 유형을 추가 할 수 있습니다 (유형이 모든 서명의 기능을 보유 할 수 있기 때문에 "any"가 붙어있습니다). 그러나 안타깝게도 이 `anyfunc` 유형은 보안상의 이유로 선형 메모리에 저장할 수 없습니다. 선형 메모리는 저장된 값의 원시 내용을 바이트로 표시하므로 wasm 내용이 임의로 웹에서 허용 하면 안되는 원시 함수 주소를 노출하거나 손상시킬 수 있습니다.

해결책은 테이블에 함수 참조를 저장하고 대신 테이블 인덱스를 전달하는 것입니다.이 인덱스는 i32 값입니다. `call_indirect`의 피연산자는 단순히 i32 인덱스 값일 수 있습니다.

#### Defining a table in wasm

그러면 우리 테이블에 함수를 어떻게 배치할까요? `data` 섹션을 사용하여 선형 메모리 영역을 바이트로 초기화하는 것처럼 `elem` 섹션을 사용하여 함수가있는 테이블 영역을 초기화 할 수 있습니다.

```rust
    (module
      (table 2 anyfunc)
      (elem (i32.const 0) $f1 $f2)
      (func $f1 (result i32)
        i32.const 42)
      (func $f2 (result i32)
        i32.const 13)
      ...
    )
```

* `(table 2 anyfunc)`에서 2는 테이블의 초기 크기 (즉, 두 개의 참조를 저장함)이고 `anyfunc`는 이러한 참조의 요소 유형이 "any signature가 있는 함수"로 선언합니다. WebAssembly의 현재 반복에서는 이것이 유일하게 허용되는 요소 유형이지만, 앞으로 더 많은 요소 유형이 추가 될 것입니다.
* 함수 (`func`) 섹션은 다른 선언 된 wasm 함수와 같습니다. 이것들은 테이블에서 참조 할 함수입니다 (예를 들어, 각각은 상수 값을 반환합니다). 섹션이 선언 된 순서는 중요하지 않습니다. 여기서는 함수를 어디에서나 선언 할 수 있으며 여전히 `elem` 섹션에서 함수를 참조 할 수 있습니다.
* `elem` 섹션은 모듈의 모든 함수 서브 세트를 순서에 상관없이 나열하며 중복을 허용 합니다. 이것은 참조되는 순서대로 테이블에서 참조 할 목록입니다.
* `elem` 섹션 내의 `(i32.const 0)` 값은 오프셋입니다. 이것은 섹션의 시작 부분에서 선언해야하며, 테이블 함수 참조가 채워지기 시작하는 인덱스를 지정합니다. 여기서 0과 2의 크기를 지정 했으므로 (위 참조) 인덱스 0과 1에서 두 개의 참조를 채울 수 있습니다. 오프셋 1에서 참조를 쓰고 싶다면 `(i32.const 1)`이고 테이블 크기는 3이어야합니다.

**참고:** 초기화되지 않은 요소에는 기본 throw-on-call 값이 제공됩니다.

자바 스크립트에서 이와 같은 테이블 인스턴스를 생성하는 호출은 다음과 같습니다.

```js
    function() {
      // table section
      var tbl = new WebAssembly.Table({initial:2, element:"anyfunc"});

      // function sections:
      var f1 = function() { … }
      var f2 = function() { … }

      // elem section
      tbl.set(0, f1);
      tbl.set(1, f2);
    };
```

#### Using the table

우리가 사용 할 테이블을 정의했습니다. 다음 코드 섹션을 통해 테이블을 사용 할 수 있습니다.

```rust
    (type $return\_i32 (func (result i32))) ;; if this was f32, type checking would fail
    (func (export "callByIndex") (param $i i32) (result i32)
      get_local $i
      call\_indirect (type $return\_i32))
```

* `(type $return_i32 (func (param i32)))` 블록은 참조 이름과 함께 유형을 지정합니다. 이 유형은 나중에 테이블 함수 참조 호출의 유형 점검을 수행 할 때 사용됩니다. 여기서 우리는 참조가 `i32`를 결과로 반환하는 함수라고 코드를 작성했습니다.
* 다음으로, `callByIndex`라는 이름으로 익스포트 될 함수를 정의합니다. 이것은 하나의 `i32`를 매개 변수로 사용하며, 인수 이름 `$i`가 주어집니다.
* Inside the function, we add one value to the stack — whatever value is passed in as the parameter `$i`. 매개 변수 `$i`로 전달되는 값이 무엇이든간에 함수 내에서 스택에 하나의 값을 추가합니다.
* 마지막으로, `call_indirect`를 사용하여 테이블에서 함수를 호출합니다. 스택에서 `$i`의 값을 암시 적으로 팝합니다. 이것의 최종 결과는 `callByIndex` 함수가 테이블에서 `$i`'th 함수를 호출한다는 것입니다.

다음과 같이 `call_indirect` 매개 변수를 명령 호출 중에 명시 적으로 선언 할 수도 있습니다.

```rust
    (call\_indirect (type $return\_i32) (get_local $i))
```

자바 스크립트와 같이 더 높은 수준의 표현력있는 언어에서는 함수가 포함 된 배열 (또는 더 많은 가능성이있는 객체)을 사용하여 동일한 작업을 수행한다고 상상할 수 있습니다. 의사 코드는 `tbl[i]()`와 유사합니다.

다시 typechecking을 보면 WebAssembly가 typechecked되고 `anyfunc`가 "모든 함수 서명"을 의미하기 때문에 callee에서 호출 수신자의 추정 서명을 제공해야하므로 `$return_i32` 유형이 포함되어 `i32`를 반환하는 함수가 예상됩니다. 호출 수신자와 일치하는 서명이 없으면 (대신 `f32`가 반환 됨) `WebAssembly.RuntimeError`가 발생합니다.

`call_indirect`와 호출하는 테이블을 연결하는 것은 무엇입니까? 대답은 모듈 인스턴스 당 하나의 테이블 만 허용된다는 것입니다. `call_indirect`가 암시 적으로 호출하는 것입니다. 향후, 여러 테이블이 허용 될 때, 우리는 또한 어떤 종류의 테이블 식별자를 지정할 필요가있습니다

```rust
    call_indirect $my\_spicy\_table (type $i32\_to\_void)
```

전체 모듈은 모두 이와 같이 보이며 wasm-table.wat 예제 파일에서 찾을 수 있습니다.

```rust
    (module
      (table 2 anyfunc)
      (func $f1 (result i32)
        i32.const 42)
      (func $f2 (result i32)
        i32.const 13)
      (elem (i32.const 0) $f1 $f2)
      (type $return\_i32 (func (result i32)))
      (func (export "callByIndex") (param $i i32) (result i32)
        get_local $i
        call\_indirect (type $return\_i32))
    )
```

다음 자바 스크립트를 사용하여 웹 페이지에로드합니다.

```js
WebAssembly.instantiateStreaming(fetch("wasm-table.wasm")).then((obj) => {
  console.log(obj.instance.exports.callByIndex(0)); // returns 42
  console.log(obj.instance.exports.callByIndex(1)); // returns 13
  console.log(obj.instance.exports.callByIndex(2)); // returns an error, because there is no index position 2 in the table
});
```

**참고:** wasm-table.html에서 이 예제를 확인할 수 있습니다. (see it live also).

**참고:** Memory와 마찬가지로 테이블은 자바 스크립트 (`WebAssembly.Table()` 참고)와 다른 wasm 모듈로 가져 오거나 다른 wasm 모듈에서 가져올 수도있다.

### Mutating tables and dynamic linking

JavaScript는 함수 참조에 대한 모든 액세스 권한을 갖기 때문에 Grow (), get () 및 set () 메서드를 통해 JavaScript에서 Table 객체를 변형 할 수 있습니다. WebAssembly에서 참조 유형을 가져 오면 WebAssembly 코드는 get\_elem / set\_elem 명령어로 테이블 자체를 변형 할 수 있습니다.

테이블은 변경 가능하기 때문에 정교한 로드 시간 및 런타임 dynamic linking schemes를 구현하는 데 사용할 수 있습니다. 프로그램이 동적으로 링크되면 여러 인스턴스가 동일한 메모리 및 테이블을 공유합니다. 이것은 여러 컴파일 된 `.dll`이 단일 프로세스의 주소 공간을 공유하는 기본 응용 프로그램과 대칭입니다.

이 작업을 보려면 Memory 객체와 Table 객체가 포함 된 단일 가져 오기 객체를 만들고 동일한 가져 오기 객체를 여러 `instantiate()` 호출에 전달합니다.

`.wat` 예제는 다음과 같습니다.

`shared0.wat`:

```rust
    (module
      (import "js" "memory" (memory 1))
      (import "js" "table" (table 1 anyfunc))
      (elem (i32.const 0) $shared0func)
      (func $shared0func (result i32)
       i32.const 0
       i32.load)
    )

`shared1.wat`:

    (module
      (import "js" "memory" (memory 1))
      (import "js" "table" (table 1 anyfunc))
      (type $void\_to\_i32 (func (result i32)))
      (func (export "doIt") (result i32)
       i32.const 0
       i32.const 42
       i32.store  ;; store 42 at address 0
       i32.const 0
       call\_indirect (type $void\_to\_i32))
    )
```

작업은 다음과 같습니다.

1. `shared0func` 함수는 `shared0.wat`에 정의되어 있으며 가져온 테이블에 저장됩니다.
2. 이 함수는 값 `0` 을 포함하는 상수를 작성한 다음 `i32.load` 명령을 사용하여 제공된 메모리 색인에 포함 된 값을로드합니다. 제공된 인덱스는 `0`입니다 - 다시 암시 적으로 스택에서 이전 값을 팝합니다. 따라서 `shared0func`는 메모리 인덱스 `0`에 저장된 값을로드하고 반환합니다.
3. `shared1.wat` 에서 `doIt`이라는 함수를 내 보냅니다.이 함수는 `0`과 `42` 값을 포함하는 두 개의 상수를 만든 다음 `i32.store`를 호출하여 제공된 값을 가져온 메모리의 제공된 색인에 저장합니다. 다시 말하지만, 스택에서이 값을 암시 적으로 팝하므로 메모리 인덱스 `0`에 값 `42`를 저장합니다.
4. 함수의 마지막 부분에서 값 0으로 상수를 만든 다음이 인덱스 0에서 `shared0func`라는 함수를 호출하고 `shared0.wat`의 `elem` 블록에 먼저 저장합니다.
5. `shared0func` 가 호출되면 `shared1.wat`의 `i32.store` 명령을 사용하여 메모리에 저장된 `42`를 로드합니다.

**참고:** **Note**: 위의 표현식은 암시 적으로 스택의 값을 다시 표시하지만 명령 호출 내에서 명시 적으로 이를 선언 할 수 있습니다. 예를 들면 다음과 같습니다.: (i32.store (i32.const 0) (i32.const 42))
 (call\_indirect (type $void\_to\_i32) (i32.const 0))

어셈블리로 변환 한 후 다음 코드를 통해 JavaScript에서 `shared0.wasm`과 `shared1.wasm`을 사용합니다.

```js
var importObj = {
  js: {
    memory: new WebAssembly.Memory({ initial: 1 }),
    table: new WebAssembly.Table({ initial: 1, element: "anyfunc" }),
  },
};

Promise.all([
  WebAssembly.instantiateStreaming(fetch("shared0.wasm"), importObj),
  WebAssembly.instantiateStreaming(fetch("shared1.wasm"), importObj),
]).then(function (results) {
  console.log(results[1].instance.exports.doIt()); // prints 42
});
```

컴파일되는 각 모듈은 동일한 메모리 및 테이블 객체를 가져와 동일한 선형 메모리 및 테이블 "주소 공간"을 공유 할 수 있습니다.

**참고:** shared-address-space.html에서 예제를 확인할 수 있습니다.(see it live also).

Summary
-------

WebAssembly 텍스트 형식의 주요 구성 요소에 대한 높은 수준의 둘러보기와 WebAssembly JS API에 반영되는 방법을 마무리합니다.

See also
--------

* 포함되지 않은 주요 내용은 함수 본문에서 발생할 수있는 모든 명령의 포괄적 인 목록입니다. 각 명령어의 처리 방법은 WebAssembly semantics을 참조하십시오.
* spec 해석기로 구현된 grammar of the text format도 참조하십시오.


WebAssembly의 개념 - 웹어셈블리

WebAssembly의 개념
===============

이번 글에서는 WebAssembly의 작동원리 뒤에 숨어있는 컨셉을 설명함과 동시에 WebAssembly의 목표, WebAssembly가 해결할 수 있는 문제, 그리고 웹브라우저 렌더링 엔진 안에서 WebAssembly가 작동하는 원리에 관해 설명하려고 합니다.

WebAssembly가 뭔가요?
-----------------

WebAssembly는 최신 웹 브라우저에서 실행할 수 있는 새로운 유형의 코드이며, 새로운 기능과 성능 면에서 큰 이점을 제공합니다. 직접 코드를 작성하는 것이 아니라 C, C++, RUST 등의 소스 언어를 효과적으로 컴파일하도록 고안되었습니다.

WebAssembly는 웹 플랫폼에 큰 영향을 미칩니다. 이전에 불가능했던 웹에서 실행되는 클라이언트 응용 프로그램을 사용하여 웹에서 여러 언어로 작성된 코드를 네이티브에 가까운 속도로 실행하는 방법을 제공합니다.

게다가 WebAssembly 코드를 생성하는 방법을 알 필요조차 없습니다. WebAssembly 모듈을 웹(또는 Node.js) 애플리케이션으로 가져와 JavaScript를 통해 사용할 수 있도록 할 수 있습니다. JavaScript 프레임워크는 WebAssembly를 사용하여 대규모 성능 이점과 새로운 기능을 제공하면서도, 웹 개발자가 쉽게 기능을 사용할 수 있도록 할 수 있습니다.

WebAssembly의 목표
---------------

WebAssembly는 W3C WebAssembly 커뮤니티 그룹에서 아래와 같은 목표로 만들어지고 있는 열린 표준입니다.

* 빠르고, 효과적이고, 이식성이 좋을 것 - WebAssembly 코드는 일반적인 하드웨어들이 제공하는 기능을 활용하여 여러 종류의 플랫폼 위에서 거의 네이티브에 가까운 속도로 실행될 수 있습니다.
* 읽기 쉽고 디버깅이 가능할 것 - WebAssembly는 저수준 어셈블리 언어지만, 직접 작성하고, 보고, 디버깅할 수 있으며 사람이 충분히 읽을 수 있는 수준의 텍스트 형식을 갖고있습니다(명세는 아직 검토중입니다).
* 안전함을 유지할 것 - WebAssembly는 샌드박싱된 실행환경에서 안전하게 돌아갈 수 있도록 설계되었습니다. 웹상의 다른 코드와 마찬가지로, WebAssembly 코드도 브라우저의 동일한 출처(same-origin)와 권한정책을 지켜야합니다.
* 웹을 망가뜨리지 않을 것 - WebAssembly는 다른 웹 기술과 마찰없이 사용되면서 하위호환성을 관리할 수 있도록 설계되었습니다.

**참고:** WebAssembly는 웹과 JavaScript 환경 밖에서도 사용될 것입니다(Non-web embeddings를 참고해주세요).

WebAssembly는 웹 플랫폼에 어떻게 적용될까요?
------------------------------

웹 플랫폼을 다음과 같이 두 부분으로 나눠서 생각해볼 수 있습니다.

* JavaScript같이 우리가 만든 앱을 구성하는 코드를 돌리는 가상머신(VM).
* 웹브라우저나 하드웨어의 기능을 호출해서 웹앱이 뭔가를 하도록 만들 수 있는 Web API의 집합 (DOM, CSSOM, WebGL, IndexedDB, Web Audio API 등).

지금까지 VM은 오직 JavaScript만 불러올 수 있었습니다. 오늘날의 웹에서 사람들이 겪고 있는 대부분의 문제를 해결하기에 JavaScript가 충분히 잘 작동했다고 볼 수 있기는 합니다. 하지만 3D 게임이나, 가상/증강현실, 컴퓨터 비전, 이미지/비디오 편집, 그 외 네이티브 성능을 필요로하는 여러 분야의 사례(WebAssembly 사용 예제 참고)에서는 성능 문제에 직면하게 됩니다.

거기에 더해서, 아주 큰 JavaScript 애플리케이션을 다운받고 구문 분석 및 컴파일하는 비용은 감당하기 힘들 수가 있습니다. 모바일 및 기타 리소스가 많이 제한된 환경에서는 이런 성능 병목현상이 더 두드러지게 나타나기도 합니다.

WebAssembly는 JavaScript와는 다른 언어이지만, JavaScript를 대체하기 위해서 만들어지지는 않았습니다. 대신 JavaScript와 나란히 돌아가면서 서로의 부족한 점을 보완하여 웹개발자가 두 언어의 강점을 동시에 취할 수 있도록 설계되었죠.

* JavaScript는 웹 애플리케이션을 작성하기에 좋은 유연하고 표현력 있는 고수준 언어입니다. 여기에는 많은 장점이 있습니다. 동적 타입 언어라 컴파일 과정이 필요 없고, 강력한 프레임워크, 라이브러리 및 기타 도구를 제공하는 거대한 생태계가 있습니다.
* WebAssembly는 네이티브에 가까운 성능으로 실행되고 C++ 및 Rust와 같이 저수준의 메모리 모델을 가진 언어의 컴파일 대상을 제공합니다. 또한, 웹에서 실행할 수 있는 컴팩트한 바이너리 형식을 갖고있는 저수준 어셈블리형 언어입니다(WebAssembly는 미래에 가비지 컬렉션 메모리 모델을 가진 언어를 지원한다는 고수준 목표도 갖고 있습니다).

브라우저에 WebAssembly가 등장하면서 앞에서 이야기했던 가상머신(VM)은 이제 JavaScript와 WebAssembly 두 가지 유형의 코드를 불러오고 실행합니다.

필요하면 다른 형식의 코드끼리 서로를 호출할 수도 있습니다. WebAssembly JavaScript API가 내보낸 WebAssembly 코드를 일반적으로 부를 수 있는 JavaScript 함수로 감싸고, WebAssembly 코드에서도 동기적으로 일반 JavaScript 함수를 호출할 수 있습니다. 사실 WebAssembly의 기본 단위는 모듈이라고 불리고, WebAssembly 모듈은 여러모로 ES6 모듈과 대칭적입니다.

### WebAssembly의 핵심 컨셉

WebAssembly가 브라우저에서 실행되는 방식을 이해하려면 필요한 몇가지 핵심 개념이 있습니다. 모든 개념은 WebAssembly JavaScript API에 1대 1로 반영되어 있습니다.

* **모듈**: 브라우저에서 실행 가능한 기계어 코드로 컴파일된 WebAssembly 바이너리를 나타냅니다. 모듈은 stateless이며 Blob처럼 Windows와 worker 간에 `postMessage()` (en-US)를 통해 명시적으로 공유 할 수 있습니다. 모듈은 ES 모듈과 마찬가지로 가져오기 및 내보내기를 선언합니다.
* **메모리**: WebAssembly의 저수준 메모리 접근 명령어에 의해 읽고 쓰여지는 바이트들의 선형 배열인, 크기 조절이 가능한 ArrayBuffer입니다.
* **테이블**: 안전성이나 이식성 이유로 원시(raw) 바이트로 메모리에 저장될 수 없는, 크기 조절 가능한 형식 지정된 배열(예, 함수)입니다.
* **인스턴스**: 모듈과 그 모듈이 사용하는 모든 상태의 쌍입니다. 모듈의 상태로는 메모리, 테이블, 가져온 값의 집합 등이 있습니다. 인스턴스는 ES 모듈처럼 특정한 전역에 특정한 가져오기의 모듈 집합과 함께 로드됩니다.

JavaScript API는 개발자에게 모듈, 메모리, 테이블 및 인스턴스를 생성하는 방법을 제공합니다. JavaScript 코드에서는, WebAssembly 인스턴스에서 일반 JavaScript 함수의 형태로 노출한 내보내기를 동기적으로 호출할 수 있습니다. WebAssembly 코드 또한, WebAssembly 인스턴스의 가져오기 형식으로 넘겨받은 임의의 JavaScript 함수를 동기적으로 호출할 수 있습니다.

WebAssembly 코드를 다운로드하고, 컴파일하고, 돌리는 일련의 과정을 온전히 JavaScript로 제어할 수 있습니다. JavaScript 개발자는 WebAssembly를 그저 효율적으로 고성능 함수를 생성하기 위한 JavaScript의 기능이라고 생각할 수도 있습니다.

앞으로, WebAssembly 모듈이(`<script type='module'>`을 사용) ES 모듈처럼 로드 가능하게 될 것입니다. ES 모듈만큼 쉽게 WebAssembly 모듈을 다운받고, 컴파일하고, 가져올 수 있습니다.

자신의 어플리케이션에서 WebAssembly를 어떻게 시작해야하나요?
--------------------------------------

위에서 WebAssembly가 웹 플랫폼에 추가하는 원시 기본 요소에 대해 이야기했습니다. 바이너리 형식과 이 바이너리 코드를 불러와서 돌리는 API가 있다는 기초 컨셉에 대해서 알아보았으니, 이제 어떻게 이 컨셉을 실제로 사용할 수 있는지 알아봅시다.

WebAssembly 생태계는 초기 단계입니다. 앞으로는 의심할 여지 없이, 더 많은 도구들이 앞으로 등장할 것입니다. 현재 4가지 방법이 있습니다.

* Emscripten으로 c/c++ 애플리케이션 포팅하기.
* 어셈블리 수준에서 바로 WebAssembly를 작성하거나 생성하기.
* Rust 응용 프로그램을 작성하고 WebAssembly를 출력으로 지정합니다.
* TypeScript와 비슷한 WebAssembly 바이너리 컴파일되는 AssemblyScript를 사용합니다.

아래 옵션에 대해 이야기해봅시다.

### C/C++로부터 포팅하기

Wasm 코드를 생성하는 다양한 옵션 중 두 가지는 온라인 Wasm 어셈블러 또는 Emscripten입니다. 아래와 같은 수많은 Wasm 어셈블러 선택 항목이 있습니다.

* WasmFiddle
* WasmFiddle++
* WasmExplorer

이것들은 어디서부터 시작해야 할지 고민하는 사람들을 위한 훌륭한 자료이지만, Emscripten과 같은 도구 및 최적화가 부족합니다.

Emscripten 도구는 거의 모든 C/C++ 소스코드를 가져와서 wasm 모듈로 컴파일하고, 모듈을 불러와서 실행하는데 필요한 JavaScript '접착제(glue)' 코드와 코드 결과를 표시하는 HTML 문서도 포함합니다.

![다이어그램: Emscripten은 C/C++ 소스 코드를 JavaScript 접착제 코드와 함께 HTML 문서인 Wasm 모듈로 컴파일합니다.](/ko/docs/WebAssembly/Concepts/emscripten-diagram.png)

핵심만 요약하면, 절차는 다음과 같습니다.

1. Emscripten은 먼저 C/C++ 소스코드를 clang+LLVM (OSX의 XCode 등에 사용될 정도로 성숙한 오픈소스 C/C++ 컴파일러 툴체인)에 넘겨줍니다.
2. Emscripten이 clang+LLVM의 컴파일 결과를 Wasm 바이너리로 변환합니다.
3. 현재 WebAssembly는 자체적으로 DOM에 바로 접근할 수가 없습니다. 정수나 부동 소수점 기초 데이터 타입을 단지 JavaScript를 호출할 수 있습니다. 따라서, 웹 API에 접근하려면 WebAssembly는 JavaScript를 호출한 다음 웹 API를 호출해야 합니다. 따라서 Emscripten은 이걸 달성하는 데 필요한 HTML과 JavaScript 접착제 코드를 같이 생성합니다.

**참고:** 나중에는 WebAssembly가 웹 API를 바로 호출하도록 허용하게 만들 계획입니다.

JavaScript 접착제 코드가 아마 여러분이 상상하는 것만큼 간단하지 않습니다. 우선 Emscripten은 SDL, OpenGL, OpenAL, POSIX의 일부와 같은 널리 사용되는 C/C++ 라이브러리를 구현합니다. 이 라이브러리는 웹 API 위에서 구현돼야하기 때문에, 기저를 이루는 웹 API에 WebAssembly를 연결시키기 위한 JavaScript 접착제 코드가 각각의 라이브러리에 있어야 합니다.

따라서, 접착제 코드의 일부는 C/C++ 코드에서 사용되는 각 라이브러리 기능을 구현하는 코드입니다. 그리고 접착제 코드에는 위에서 언급한 WebAssembly JavaScript API를 사용해서 Wasm 파일을 로드하고 실행하는 논리도 같이 담고 있습니다.

생성된 HTML 문서는 JavaScript 접착제 코드를 불러오고 표준 출력(stdout)을 `<textarea>` (en-US)에 작성합니다. 만약 애플리케이션이 OpenGL을 사용하고 있으면, HTML 안에 렌더링 대상으로 사용되는 `<canvas>` 요소가 포함됩니다. 이 Emscripten 출력을 여러분의 웹 애플리케이션에 맞게 뜯어고치는 작업은 매우 쉽습니다.

Emscripten에 대한 전체 문서는 emscripten.org에서 볼 수 있습니다. 툴체인을 구성하고 C/C++ 애플리케이션을 Wasm로 컴파일하는 방법은 Compiling from C/C++ to WebAssembly 문서를 참고하세요.

### WebAssembly를 직접 작성하기

런타임에 WebAssembly를 생성하는 JavaScript 라이브러리나, 여러분만의 컴파일러 또는 도구를 직접 만들고 싶으신가요?

실제 하드웨어 어셈블리 언어와 동일한 방식으로, WebAssembly의 바이너리 형식에도 1:1로 대응하는 문자형 표현이 존재합니다. WebAssembly 텍스트를 바이너리로 바꿔주는 도구들을 활용해서 직접 작성한 텍스트 형식을 바이너리 형식으로 변환시켜볼 수 있습니다.

WebAssembly 텍스트 형식을 Wasm으로 변환하기에서는 이를 어떻게 하는지 간단하게 설명해줍니다.

### Rust로 WebAssembly 작성하기

Rust WebAssembly 워킹 그룹의 끊임없는 노력 덕분에, Rust 코드를 작성하고 WebAssembly로 컴파일 할 수 있습니다. 필요한 툴 체인을 설치하고, 샘플 Rust 프로그램을 WebAssembly npm 패키지로 컴파일하고, 샘플 웹 애플리케이션의 샘플 Compiling from Rust to WebAssembly 글을 통해 시작할 수 있습니다.

### AssemblyScript 사용하기

Rust 혹은 C를 자세히 배우지 않고, WebAssembly를 사용해 보고 TypeScript와 같은 친숙한 언어를 편안하게 사용하려는 웹 개발자에게는 AssemblyScript는 최고의 선택지입니다. AssemblyScript는 TypeScript의 엄격한 변형을 WebAssembly로 컴파일하므로 웹 개발자는 Prettier, ESLint, VS Code IntelliSense 등과 같이 익숙한 TypeScript 호환 도구를 계속 사용할 수 있습니다. https://docs.assemblyscript.org/ 문서에서 확인해 보실 수 있습니다.

요약
--

이 글에서는 WebAssembly가 무엇이고, 왜 유용한지, 웹에 어떻게 적용되는지, 어떻게 활용할 수 있는지에 대해 설명합니다.

같이 보기
-----

* Mozilla Hacks 블로그의 WebAssembly 글
* Mozilla 연구의 WebAssembly 사용
* WebAssembly 코드 로드 및 실행 - WebAssembly 모듈을 웹 페이지에 로드하는 방법을 알아보세요.
* WebAssembly JavaScript API 사용하기 - WebAssembly JavaScript API의 다른 주요 기능을 사용하는 방법을 알아보세요.


WebAssembly.validate() - 웹어셈블리

WebAssembly.validate()
======================

**`WebAssembly.validate()`** 함수는 바이트가 유효한 wasm 모듈을 형성하는지 (`true`) 또는 생성하지 않는지 (`false`)를 반환하여 WebAssembly 바이너리 코드의 지정된 typed array의 유효성을 검사합니다.

Syntax
------
```

WebAssembly.validate(bufferSource);
```
### Parameters

`bufferSource`

유효성을 검사 할 WebAssembly 바이너리 코드가 들어있는 typed array 또는 ArrayBuffer입니다.

### Return value

`bufferSource`가 유효한 wasm 코드 (`true`)인지 아닌지 (`false`)를 지정하는 부울입니다.

### Exceptions

`bufferSource`가 typed array이나 ArrayBuffer가 아닌 경우 `TypeError`가 발생합니다.

Examples
--------

다음 예제 (validate.html source code 참조 및 see it live)는 .wasm 모듈을 가져 와서 형식화 된 배열로 변환합니다. 그런 다음 `validate()` 메서드를 사용하여 모듈이 유효한지 확인합니다.

```js
fetch("simple.wasm")
  .then((response) => response.arrayBuffer())
  .then(function (bytes) {
    var valid = WebAssembly.validate(bytes);
    console.log(
      "The given bytes are " + (valid ? "" : "not ") + "a valid wasm module",
    );
  });
```

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # dom-webassembly-validate |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.compile() - 웹어셈블리

WebAssembly.compile()
=====================

\*\*`WebAssembly.compile()`\*\*함수는 WebAssembly 바이너리 코드에서 `WebAssembly.Module`을 컴파일합니다. 이 함수는 모듈을 인스턴스화하기 전에 컴파일해야하는 경우에 유용합니다. 그렇지 않으면 `WebAssembly.instantiate ()` 함수를 사용해야합니다.

Syntax
------

```js
WebAssembly.compile(bufferSource);
```

### Parameters

*bufferSource*

컴파일 할 .wasm 모듈의 이진 코드가 들어있는 typed array 또는 ArrayBuffer입니다.

### Return value

`Promise`는 컴파일 된 모듈로 표현된 `WebAssembly.Module` 객체로 반환됩니다.

### Exceptions

* `bufferSource`가 typed array가 아니면 `TypeError`가 발생합니다.
* 컴파일에 실패하면 promise는 `WebAssembly.CompileError`와 함께 reject가 반환됩니다.
Examples
--------

다음은 `compile()` 함수를 사용하여 simple.wasm 바이트 코드를 컴파일 하고 postMessage() (en-US)를 사용하여 worker에 보내는 예제입니다.

```js
var worker = new Worker("wasm\_worker.js");

fetch("simple.wasm")
  .then((response) => response.arrayBuffer())
  .then((bytes) => WebAssembly.compile(bytes))
  .then((mod) => worker.postMessage(mod));
```

**참고:** 대부분의 경우에 `WebAssembly.compileStreaming()`를 사용하는 것이 좋습니다. 이는 `compile()`보다 효율적이기 때문입니다.

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # dom-webassembly-compile |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.Table() - 웹어셈블리

WebAssembly.Table()
===================

**`WebAssembly.Table()`** 생성자는 지정된 크기 및 요소 유형의 새 `Table` 객체를 만듭니다.

이것은 자바 스크립트 래퍼 객체로, 함수 참조를 저장하는 WebAssembly 테이블을 나타내는 배열과 같은 구조입니다. JavaScript 또는 WebAssembly 코드로 작성된 테이블은 JavaScript 및 WebAssembly에서 액세스 및 변경할 수 있습니다.

**참고:** 테이블은 현재 function references만 저장할 수 있지만 나중에 확장 될 수 있습니다.

Syntax
------

```js
var myTable = new WebAssembly.Table(tableDescriptor);
```

### Parameters

*tableDescriptor*

 다음 멤버를 포함 할 수있는 객체입니다:\_ *element*
 \_ : 테이블에 저장 될 값 유형을 나타내는 문자열. 현재로서는 `"anyfunc"`(함수) 값만있을 수 있습니다.

*initial*

WebAssembly 테이블의 초기 요소 수입니다.

*maximum Optional*

WebAssembly 테이블의 최대 증가 요소 수입니다.

### Exceptions

* `tableDescriptor`가 object 유형이 아닌 경우 `TypeError`가 발생합니다.
* `maximum`이 지정되고 initial보다 작은 경우 `RangeError`가 발생합니다.
`Table` instances
-----------------

모든 `Table` 인스턴스는 `Table()`생성자의 prototype object (en-US)에서 상속받습니다.이 인스턴스는 모든 `Table` 인스턴스에 적용되도록 수정할 수 있습니다.

### Instance properties

`Table.prototype.constructor`

이 객체의 인스턴스를 생성 한 함수를 돌려줍니다. 기본적으로 이것은 `WebAssembly.Table()` 생성자입니다.

`Table.prototype.length` (en-US)

테이블의 길이, 즉 요소의 수를 돌려줍니다.

### Instance methods

`Table.prototype.get()` (en-US)

접근 자 함수 - 주어진 색인에 저장된 요소를 가져옵니다.

`Table.prototype.grow()` (en-US)

지정된 요소 수만큼 Table 인스턴스의 크기를 늘립니다.

`Table.prototype.set()` (en-US)

지정된 인덱스에 격납되어있는 요소를, 지정된 값으로 설정합니다.

Examples
--------

다음 예제 (table2.html source code 및 live version 참조)는 초기 크기가 2인 새 WebAssembly Table 인스턴스를 만듭니다. 그런 다음 두 개의 인덱스 (표 `Table.prototype.get ()`를 통해 검색하여 테이블의 길이와 내용을 인쇄합니다. 길이가 2이고 `null`이 두개라고 출력됩니다.

```js
var tbl = new WebAssembly.Table({ initial: 2, element: "anyfunc" });
console.log(tbl.length); // "2"
console.log(tbl.get(0)); // "null"
console.log(tbl.get(1)); // "null"
```

그런 다음 테이블을 포함한 `importObj`를 만듭니다.

```js
var importObj = {
  js: {
    tbl: tbl,
  },
};
```

마지막으로 `WebAssembly.instantiateStreaming ()` 메소드를 사용하여 wasm 모듈 (table2.wasm)을 로드하고 인스턴스화합니다. table2.wasm 모듈에는 두 개의 함수 (하나는 42를 반환하고 다른 하나는 83을 반환하는 함수)가 들어 있고 가져온 테이블의 요소 0과 1에 둘 다 저장합니다 (text representation 참조). 인스턴스화 후에도 테이블의 길이는 여전히 2이지만 JS에 호출 할 수있는 호출 가능한 Exported WebAssembly Functions가 요소에 포함됩니다.

```js
WebAssembly.instantiateStreaming(fetch("table2.wasm"), importObject).then(
  function (obj) {
    console.log(tbl.length);
    console.log(tbl.get(0)());
    console.log(tbl.get(1)());
  },
);
```

액세서의 끝 부분에 두 번째 함수 호출 연산자를 포함시켜 실제로 참조 된 함수를 호출하고 그 안에 저장된 값을 기록해야합니다 (예 : `get(0)` 대신 `get(0)()`).

이 예제는 자바 스크립트에서 테이블을 만들고 액세스하고 있지만 wasm 인스턴스 내부에서도 같은 테이블을 볼 수 있고 호출 할 수 있음을 보여줍니다.

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # tables |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.Instance - 웹어셈블리

WebAssembly.Instance
====================

**`WebAssembly.Instance`** 개체는 WebAssembly.Module의 상태 저장되고 실행 가능한 인스턴스입니다. `Instance` 객체에는 JavaScript에서 WebAssembly 코드로 호출 할 수있는 모든 Exported WebAssembly functions가 포함되어 있습니다.

주어진 `WebAssembly.Module` 객체를 동기적으로 인스턴스화하기 위해 `WebAssembly.Instance()` 생성자 함수를 호출 할 수 있습니다. 하지만 `Instance`를 가져 오는 주요 방법은 비동기 `WebAssembly.instantiateStreaming ()` 함수를 사용하는 것입니다.

생성자
---

`WebAssembly.Instance()` (en-US)

Creates a new `Instance` object.

인스턴스 속성
-------

`Instance.prototype.exports` (en-US)

Returns an object containing as its members all the functions exported from the WebAssembly module instance, to allow them to be accessed and used by JavaScript. Read-only.

명세
--

| Specification |
| --- |
| WebAssembly JavaScript Interface # instances |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.CompileError() - 웹어셈블리

WebAssembly.CompileError()
==========================

\*\*`WebAssembly.CompileError()`\*\*생성자는 WebAssembly 디코딩 또는 유효성 검사 중에 발생한 오류를 나타내는 WebAssembly `CompileError` 객체를 새로 만듭니다.

Syntax
------

```js
new WebAssembly.CompileError(message, fileName, lineNumber);
```

### Parameters

`message` Optional

사람이 읽을수 있는 형태의 에러에 대한 설명.

`fileName` Optional
비표준

예외의 원인이 된 코드가 들어있는 파일의 이름입니다.

`lineNumber` Optional
비표준

예외의 원인이 된 코드의 행 번호입니다.

Properties
----------

*`CompileError` 생성자에는 고유 한 고유 속성이 없지만 프로토 타입 체인을 통해 일부 속성을 상속합니다.*

`WebAssembly.CompileError.prototype.constructor`

인스턴스의 프로토 타입을 작성한 함수를 지정합니다.

`WebAssembly.CompileError.prototype.message`

에러 메시지. ECMA-262는 `URIError`가 SpiderMonkey에서 자체 `message` 속성을 제공하도록 지정했지만 `Error.prototype.message`를 상속받습니다.

`WebAssembly.CompileError.prototype.name`

에러 명칭. `Error`에서 상속합니다.

`WebAssembly.CompileError.prototype.fileName`

에러가 발생한 파일의 경로. `Error`에서 상속합니다.

`WebAssembly.CompileError.prototype.lineNumber`

에러가 발생한 파일의 코드 줄번호. `Error`에서 상속합니다.

`WebAssembly.CompileError.prototype.columnNumber`

에러가 발생한 줄의 열 번호. `Error`에서 상속합니다.

`WebAssembly.CompileError.prototype.stack` (en-US)

스텍 추적. `Error`에서 상속합니다.

Methods
-------

*`CompileError`* 생성자에는 자체 메서드가 없지만 프로토 타입 체인을 통해 일부 메서드를 상속합니다.

`WebAssembly.CompileError.prototype.toSource()` (en-US)

동일한 오류로 판단할 수 있는 코드를 반환합니다. `Error`에서 상속합니다.

`WebAssembly.CompileError.prototype.toString()`

지정된 Error 객체를 나타내는 문자열을 반환합니다. `Error`에서 상속합니다.

Examples
--------

다음 스 니펫은 새 `CompileError` 인스턴스를 만들고 콘솔에 세부 정보를 기록합니다.

```js
try {
  throw new WebAssembly.CompileError("Hello", "someFile", 10);
} catch (e) {
  console.log(e instanceof CompileError); // true
  console.log(e.message); // "Hello"
  console.log(e.name); // "CompileError"
  console.log(e.fileName); // "someFile"
  console.log(e.lineNumber); // 10
  console.log(e.columnNumber); // 0
  console.log(e.stack); // returns the location where the code was run
}
```

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # exceptiondef-compileerror |
| ECMAScript Language Specification # sec-native-error-types-used-in-this-standard |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.instantiate() - 웹어셈블리

WebAssembly.instantiate()
=========================

**`WebAssembly.instantiate()`** 함수를 사용하면 WebAssembly 코드를 컴파일하고 인스턴스화 할 수 있습니다. 이 함수에는 두개의 overloads가 있습니다.

* 기본 오버로드는 typed array 또는 `ArrayBuffer`의 형태로 WebAssembly 바이너리 코드를 취해 컴파일 및 인스턴스화를 한 번에 수행합니다. 반환 된 Promise는 컴파일 된 `WebAssembly.Module` 및 첫 번째 `WebAssembly.Instance`로 해석됩니다.
* 두번째 오버로드는 이미 컴파일 된 `WebAssembly.Module`을 취하여 해당 `Module`의 `Instance`로 해석되는 `Promise`을 반환합니다. 이 overload는 `Module`이 이미 컴파일된 경우 유용합니다.

**경고:** **중요 :** **이 방법은 wasm 모듈을 가져와 인스턴스화하는 가장 효율적인 방법은 아닙니다. 가능하다면 원시 바이트 코드에서 모듈을 모두 한 단계로 가져오고, 컴파일하고 인스턴스화하는 대신 최신 `WebAssembly.instantiateStreaming ()` 메서드를 사용해야합니다. `ArrayBuffer` 로의 변환이 필요합니다.**

Syntax
------

### Primary overload — taking wasm binary code
```

Promise<ResultObject> WebAssembly.instantiate(bufferSource, importObject);
```

#### Parameters

*bufferSource*

컴파일 할 .wasm 모듈의 이진 코드가 들어있는 typed array 또는 `ArrayBuffer`입니다.

*importObject* Optional

함수 또는 `WebAssembly.Memory` 객체와 같이 새로 생성 된 `인스턴스`로 가져올 값을 포함하는 객체입니다. 컴파일 된 모듈의 각 선언 된 가져 오기에 대해 하나의 일치하는 속성이 있어야합니다. 그렇지 않으면 `WebAssembly.LinkError`가 발생합니다.

#### Return value

두개의 필드를 포함하는 `ResultObject`를 가진 `Promise`를 반환:

* `module`: 컴파일 된 WebAssembly 모듈을 나타내는 `WebAssembly.Module` 객체입니다. 이 `Module`은 `postMessage()` (en-US)를 통해 공유되거나 cached in IndexedDB로 다시 인스턴스화 될 수 있습니다.
* `instance`: Exported WebAssembly functions을 포함하는 `WebAssembly.Instance` 객체입니다.

#### Exceptions

* 매개 변수 중 하나가 올바른 유형 또는 구조가 아니면 `TypeError`가 발생합니다.
* 작업이 실패하면 promise는 실패 원인에 따라 `WebAssembly.CompileError`, `WebAssembly.LinkError` 또는 `WebAssembly.RuntimeError`로 reject됩니다.
### Secondary overload — taking a module object instance
```

Promise<WebAssembly.Instance> WebAssembly.instantiate(module, importObject);
```

#### Parameters

*module*

`WebAssembly.Module` 객체가 인스턴스화됩니다.

*importObject* Optional

함수 또는 `WebAssembly.Memory` 객체와 같이 새로 생성 된 인스턴스로 가져올 값을 포함하는 객체입니다. 선언 된 각 `module` 가져 오기에 대해 일치하는 속성이 하나 있어야합니다. 그렇지 않으면 `WebAssembly.LinkError` 가 발생합니다.

#### Return value

A `Promise` that resolves to an `WebAssembly.Instance` object.

#### Exceptions

* 매개 변수 중 하나가 올바른 유형 또는 구조가 아니면 `TypeError`가 발생합니다.
* If the operation fails, the promise rejects with a `WebAssembly.CompileError`, `WebAssembly.LinkError`, or `WebAssembly.RuntimeError`, depending on the cause of the failure.
 작업이 실패하면 promise는 실패 원인에 따라 `WebAssembly.CompileError`, `WebAssembly.LinkError` 또는 `WebAssembly.RuntimeError`로 reject됩니다.
Examples
--------

**Note**: 대부분의 경우 `instantiate()`보다 더 효율적이므로 `WebAssembly.instantiateStreaming ()`을 사용하는 것이 좋습니다.

### First overload example

fetch를 사용하여 일부 WebAssembly 바이트 코드를 가져온 후 우리는 `WebAssembly.instantiate ()` 함수를 사용하여 모듈을 컴파일하고 인스턴스화하여 해당 프로세스에서 JavaScript 함수를 WebAssembly 모듈로 가져옵니다. 그런 다음 `Instance`에서 Exported WebAssembly function를 호출합니다.

```js
var importObject = {
  imports: {
    imported\_func: function (arg) {
      console.log(arg);
    },
  },
};

fetch("simple.wasm")
  .then((response) => response.arrayBuffer())
  .then((bytes) => WebAssembly.instantiate(bytes, importObject))
  .then((result) => result.instance.exports.exported\_func());
```

**참고:** 이 예제는 GitHub의 index.html에서도 찾을 수 있습니다 (라이브보기도 있음).

### Second overload example

다음 예제는 (GitHub의 index-compile.html 데모 혹은 라이브로 보기). `WebAssembly.compileStreaming ()` 메서드를 사용하여 로드된 simple.wasm 바이트 코드를 컴파일 한 다음 `postMessage()` (en-US)를 사용하여 worker에게 전달합니다.

```js
var worker = new Worker("wasm\_worker.js");

WebAssembly.compileStreaming(fetch("simple.wasm")).then((mod) =>
  worker.postMessage(mod),
);
```

작업자 (`wasm_worker.js` 참조)에서 모듈이 사용할 가져 오기 객체를 정의한 다음 주 스레드에서 모듈을 수신 할 이벤트 핸들러를 설정합니다. 모듈을 받으면 `WebAssembly.instantiate ()` 메소드를 사용하여 인스턴스를 만들고 내부에서 내 보낸 함수를 호출합니다.

```js
var importObject = {
  imports: {
    imported\_func: function (arg) {
      console.log(arg);
    },
  },
};

onmessage = function (e) {
  console.log("module received from main thread");
  var mod = e.data;

  WebAssembly.instantiate(mod, importObject).then(function (instance) {
    instance.exports.exported\_func();
  });
};
```

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # dom-webassembly-instantiate |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.compileStreaming() - 웹어셈블리

WebAssembly.compileStreaming()
==============================

\*\*`WebAssembly.compileStreaming()`\*\*함수는 스트림 된 원본 소스에서 직접 `WebAssembly.Module`을 컴파일합니다. 이 함수는 모듈을 인스턴스화하기 전에 컴파일해야하는 경우 유용합니다 (그렇지 않으면 `WebAssembly.instantiateStreaming ()` 함수를 사용해야합니다).

Syntax
------

```js
WebAssembly.compileStreaming(source);
```

### Parameters

*source*

스트리밍 및 컴파일하려는 .wasm 모듈의 기본 소스를 나타내는 `Response` 객체 또는 약속을 수행합니다.

### Return value

`Promise`는 컴파일 된 모듈로 표현된 `WebAssembly.Module` 객체로 반환됩니다.

### Exceptions

* `bufferSource`가 typed array가 아니면 `TypeError`가 발생합니다.
* 컴파일에 실패하면 promise는 `WebAssembly.CompileError`와 함께 reject가 반환됩니다.
Examples
--------

다음 예제 (GitHub의 compile-streaming.html 데모 및 라이브보기)에서 기본 소스의 .wasm 모듈을 직접 스트리밍 한 다음 `WebAssembly.Module` 객체로 컴파일합니다. `compileStreaming()` 함수는 `Response` 객체에 대한 promise를 받으므로 직접 `fetch()` 호출을 전달할 수 있습니다.

```js
var importObject = { imports: { imported\_func: (arg) => console.log(arg) } };

WebAssembly.compileStreaming(fetch("simple.wasm"))
  .then((module) => WebAssembly.instantiate(module, importObject))
  .then((instance) => instance.exports.exported\_func());
```

결과 모듈 인스턴스는 `WebAssembly.instantiate ()`를 사용하여 인스턴스화되고 내 보낸 함수가 호출됩니다.

명세서
---

| Specification |
| --- |
| WebAssembly Web API # dom-webassembly-compilestreaming |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.Module - 웹어셈블리

WebAssembly.Module
==================

**`WebAssembly.Module`** 객체는 브라우저에서 이미 컴파일 된 stateless WebAssembly 코드를 포함하며 효율적으로 Workers와 공유 (en-US)하고 여러 번 인스턴스화 할 수 있습니다. 모듈을 인스턴스화하려면 WebAssembly.instantiate() 2차 오버로드를 호출하세요.

`WebAssembly.Module()` 생성자 함수를 호출하여 지정된 WebAssembly 바이너리 코드를 동기식으로 컴파일 할 수 있습니다. 그러나 `Module`을 쓰는 주된 방법은 `WebAssembly.compile ()`과 같은 비동기 컴파일 함수를 사용하는 것입니다.

생성자
---

`WebAssembly.Module()` (en-US)

Creates a new `Module` object.

정적 속성
-----

`WebAssembly.Module.customSections()` (en-US)

모듈(`Module`)과 문자열이 주어지면 모듈의 모든 사용자 정의 섹션 내용의 사본을 주어진 문자열 이름으로 반환합니다.

`WebAssembly.Module.exports()` (en-US)

모듈(`Module`)이 주어지면 선언 된 모든 내보내기에 대한 설명이 들어있는 배열을 반환합니다.

`WebAssembly.Module.imports()` (en-US)

모듈(`Module`)이 주어지면 선언 된 모든 가져오기에 대한 설명이 들어있는 배열을 반환합니다.

명세
--

| Specification |
| --- |
| WebAssembly JavaScript Interface # modules |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.LinkError() - 웹어셈블리

WebAssembly.LinkError()
=======================

The **`WebAssembly.LinkError()`** constructor creates a new WebAssembly `LinkError` object, which indicates an error during module instantiation (besides traps from the start function).

**`WebAssembly.LinkError()`** 생성자는 새 WebAssembly `LinkError` 객체를 만듭니다. 이 객체는 모듈 인스턴스화 중의 오류를 나타냅니다 (시작 함수의 traps와 함께).

Syntax
------

```js
new WebAssembly.LinkError(message, fileName, lineNumber);
```

### Parameters

`message` Optional

사람이 읽을 수 있는 오류 설명.

`fileName` Optional
비표준

예외의 원인이 된 코드가 들어있는 파일의 이름입니다.

`lineNumber` Optional
비표준

예외의 원인이 된 코드의 행 번호입니다.

Properties
----------

*`LinkError`* 생성자에는 고유 한 고유 속성이 없지만 프로토 타입 체인을 통해 일부 속성을 상속합니다.

`WebAssembly.LinkError.prototype.constructor`

인스턴스의 프로토 타입을 작성한 함수를 지정합니다.

`WebAssembly.LinkError.prototype.message`

에러 메시지. ECMA-262는 `URIError`가 SpiderMonkey에서 자체 `message` 속성을 제공하도록 지정했지만 `Error.prototype.message`를 상속받습니다.

`WebAssembly.LinkError.prototype.name`

에러 이름. `Error`를 상속받습니다.

`WebAssembly.LinkError.prototype.fileName`

해당 에러가 발생한 파일의 경로. `Error`를 상속받습니다.

`WebAssembly.LinkError.prototype.lineNumber`

에러가 발생한 파일의 행 번호. `Error`를 상속받습니다.

`WebAssembly.LinkError.prototype.columnNumber`

이 오류가 발생한 행의 열 번호입니다.. `Error`를 상속받습니다.

`WebAssembly.LinkError.prototype.stack` (en-US)

스텍 추적. `Error`를 상속받습니다.

Methods
-------

*`LinkError`* 생성자에는 자체 메서드가 없지만 프로토 타입 체인을 통해 일부 메서드를 상속합니다.

`WebAssembly.LinkError.prototype.toSource()` (en-US)

동일한 오류로 평가 될 수있는 코드를 반환합니다. `Error`를 상속받습니다.

`WebAssembly.LinkError.prototype.toString()`

지정된 Error 객체를 나타내는 문자열을 반환합니다. `Error`를 상속받습니다.

Examples
--------

다음 snippet은 새 `LinkError` 인스턴스를 만들고 콘솔에 세부 정보를 기록합니다.

```js
try {
  throw new WebAssembly.LinkError("Hello", "someFile", 10);
} catch (e) {
  console.log(e instanceof LinkError); // true
  console.log(e.message); // "Hello"
  console.log(e.name); // "LinkError"
  console.log(e.fileName); // "someFile"
  console.log(e.lineNumber); // 10
  console.log(e.columnNumber); // 0
  console.log(e.stack); // returns the location where the code was run
}
```

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # exceptiondef-linkerror |
| ECMAScript Language Specification # sec-native-error-types-used-in-this-standard |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.Memory() - 웹어셈블리

WebAssembly.Memory()
====================

**`WebAssembly.Memory()`** 생성자는 WebAssembly `Instance`가 액세스하는 메모리의 원시 바이트를 가진 ArrayBuffer(크기조정이 가능)인 새 `Memory` 객체를 만듭니다.

메모리는 JavaScript 혹은 WebAssembly 코드 안에서 만들어지며 JavaScript 그리고 WebAssembly에서 접근하거나 변경이 가능합니다.

Syntax
------

```js
var myMemory = new WebAssembly.Memory(memoryDescriptor);
```

### Parameters

*memoryDescriptor*

 다음의 멤버를 가질수 있는 객체입니다.\_ *initial*
 \_ : WebAssembly Page의 단위별 WebAssembly 메모리의 초기 크기입니다.

*maximum Optional*

WebAssembly 메모리의 최대 크기는 WebAssembly 페이지 단위로 증가 할 수 있습니다. 이 매개 변수가 있으면 `maximum` 매개 변수는 엔진에 대해 메모리를 전면에 예약하도록 합니다. 그러나 엔진은 이 예약 요청을 무시하거나 클램핑 할 수 있습니다. 일반적으로 대부분의 WebAssembly 모듈은 `maximum` 값을 설정할 필요가 없습니다.

**참고:** WebAssembly 페이지의 크기는 65,536 바이트로 64KiB로 고정되어 있습니다.

### Exceptions

* `memoryDescriptor`가 object 유형이 아닌 경우 `TypeError`가 발생합니다.
* `maximum`이 지정되고 `initial`보다 작은 경우 `RangeError`가 발생합니다.
`Memory` instances
------------------

모든 `Memory` 인스턴스는 `Memory()`생성자의 prototype object (en-US)를 상속합니다.이 인스턴스는 모든 `Memory` 인스턴스에 적용되도록 수정할 수 있습니다.

### Instance properties

`Memory.prototype.constructor`

이 객체의 인스턴스를 생성 한 함수를 돌려줍니다. 기본적으로 이것은 `WebAssembly.Memory()` 생성자입니다.

`Memory.prototype.buffer` (en-US)

메모리에 포함 된 버퍼를 반환하는 접근 자 속성입니다.

### Instance methods

`Memory.prototype.grow()` (en-US)

지정된 수의 WebAssembly 페이지 (각각 64KB 크기)만큼 메모리 인스턴스의 크기를 늘립니다.

Examples
--------

`WebAssembly.Memory` 객체를 가져 오는 두 가지 방법이 있습니다. 첫 번째 방법은 JavaScript에서 생성하는 것입니다. 다음 예제에서는 초기 크기가 10 페이지 (640KiB)이고 최대 크기가 100 페이지 (6.4MiB) 인 새 WebAssembly 메모리 인스턴스를 만듭니다.

```js
var memory = new WebAssembly.Memory({ initial: 10, maximum: 100 });
```

`WebAssembly.Memory` 객체를 가져 오는 두 번째 방법은 WebAssembly 모듈에서 내보냅니다. 다음 예제는 (GitHub의 memory.html을 보세요. 라이브로 보기) 생성된 메모리를 가져 오는 동안 `WebAssembly.instantiateStreaming()` 메소드를 사용하여로드 된 memory.wasm 바이트 코드를 가져 와서 인스턴스화합니다. 위의 줄에. 그런 다음 메모리에 일부 값을 저장 한 다음 함수를 내 보낸 다음 일부 값의 합계에 사용합니다.

```js
WebAssembly.instantiateStreaming(fetch("memory.wasm"), {
  js: { mem: memory },
}).then((obj) => {
  var i32 = new Uint32Array(memory.buffer);
  for (var i = 0; i < 10; i++) {
    i32[i] = i;
  }
  var sum = obj.instance.exports.accumulate(0, 10);
  console.log(sum);
});
```

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # memories |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.RuntimeError() - 웹어셈블리

WebAssembly.RuntimeError()
==========================

**`WebAssembly.RuntimeError()`** 생성자는 WebAssembly에서 trap을 지정할 때마다 throw되는 새 WebAssembly `RuntimeError` 객체를 만듭니다.

Syntax
------

```js
new WebAssembly.RuntimeError(message, fileName, lineNumber);
```

### Parameters

`message` Optional

인간이 읽을 수있는 오류 설명.

`fileName` Optional
비표준

예외의 원인이 된 코드가 들어있는 파일의 이름입니다.

`lineNumber` Optional
비표준

예외의 원인이 된 코드의 행 번호입니다.

Properties
----------

*`RuntimeError` 생성자에는 고유 한 고유 속성이 없지만 프로토 타입 체인을 통해 일부 속성을 상속합니다.*

`WebAssembly.RuntimeError.prototype.constructor`

인스턴스의 프로토 타입을 작성한 함수를 지정합니다.

`WebAssembly.RuntimeError.prototype.message`

에러 메시지. ECMA-262는 `URIError`가 SpiderMonkey에서 자체 `message` 속성을 제공하도록 지정했지만 `Error.prototype.message`를 상속받습니다.

`WebAssembly.RuntimeError.prototype.name`

오류 이름. `Error`에서 상속됩니다.

`WebAssembly.RuntimeError.prototype.fileName`

이 오류를 발생시킨 파일의 경로입니다. `Error`에서 상속됩니다.

`WebAssembly.RuntimeError.prototype.lineNumber`

이 오류가 발생한 파일의 행 번호입니다. `Error`에서 상속됩니다.

`WebAssembly.RuntimeError.prototype.columnNumber`

이 오류가 발생한 행의 열 번호입니다. `Error`에서 상속됩니다.

`WebAssembly.RuntimeError.prototype.stack` (en-US)

스택 추적. `Error`에서 상속됩니다.

Methods
-------

*`RuntimeError` 생성자에는 자체 메서드가 없지만 프로토 타입 체인을 통해 일부 메서드를 상속합니다.*

`WebAssembly.RuntimeError.prototype.toSource()` (en-US)

동일한 오류로 평가 될 수있는 코드를 반환합니다. `Error`에서 상속됩니다.

`WebAssembly.RuntimeError.prototype.toString()`

지정된 `Error` 객체를 나타내는 문자열을 반환합니다. `Error`에서 상속됩니다.

Examples
--------

다음의 스니펫은, 새로운 RuntimeError 인스턴스를 작성해, 그 상세를 콘솔에 기록합니다.

```js
try {
  throw new WebAssembly.RuntimeError("Hello", "someFile", 10);
} catch (e) {
  console.log(e instanceof RuntimeError); // true
  console.log(e.message); // "Hello"
  console.log(e.name); // "RuntimeError"
  console.log(e.fileName); // "someFile"
  console.log(e.lineNumber); // 10
  console.log(e.columnNumber); // 0
  console.log(e.stack); // returns the location where the code was run
}
```

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # exceptiondef-runtimeerror |
| ECMAScript Language Specification # sec-native-error-types-used-in-this-standard |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


WebAssembly.Global - 웹어셈블리

WebAssembly.Global
==================

**`WebAssembly.Global`** 객체는 전역 변수 인스턴스를 나타내며 JavaScript 및 하나 이상의 `WebAssembly.Module` 인스턴스에서 가져오거나 내보낼 수 있습니다. 이렇게 하면 여러 모듈을 동적으로 연결할 수 있습니다.

생성자
---

`WebAssembly.Global()` (en-US)

새로운 `Global` 객체를 생성합니다.

전역 인스턴스
-------

모든 `Global` 인스턴스는 `Global()` 생성자의 프로토타입 객체에서 상속합니다. 모든 `Global` 인스턴스에 영향을 미치도록 수정할 수 있습니다.

### 인스턴스 속성

`Global.prototype.constructor`

이 객체의 인스턴스를 생성한 함수를 반환합니다. 기본적으로 이것은 `WebAssembly.Global()` 생성자입니다.

`Global.prototype[@@toStringTag]`

@@toStringTag (en-US) 프로퍼티의 초기값은 문자열 값 "WebAssembly.Global" 입니다.

`Global.prototype.value`

전역 변수 내부에 포함된 값 - 전역 값을 직접 설정하고 가져오는 데 사용할 수 있습니다.

### 인스턴스 메서드

`Global.prototype.valueOf()`

전역 변수 내부에 포함된 값을 반환하는 구식 메소드입니다.

Examples
--------

다음 예제에서는 `WebAssembly.Global()` 생성자를 사용하여 만드는 새 전역 인스턴스를 보여줍니다. 값이 0 인 변경 가능한 `i32` 유형으로 정의됩니다.

먼저 `Global.value` 속성을 사용하여 '42'로 전역 값이 변경되고, `global.wasm` 모듈에서 내보낸 `incGlobal()` 함수를 사용하여 43으로 변경됩니다. (이 함수는 주어진 값에 1을 더한 다음 새 값을 반환합니다).

```js
const output = document.getElementById("output");

function assertEq(msg, got, expected) {
  output.innerHTML += `Testing ${msg}: `;
  if (got !== expected)
    output.innerHTML += `FAIL!<br>Got: ${got}<br>Expected: ${expected}<br>`;
  else output.innerHTML += `SUCCESS! Got: ${got}<br>`;
}

assertEq("WebAssembly.Global exists", typeof WebAssembly.Global, "function");

const global = new WebAssembly.Global({ value: "i32", mutable: true }, 0);

WebAssembly.instantiateStreaming(fetch("global.wasm"), { js: { global } }).then(
  ({ instance }) => {
    assertEq(
      "getting initial value from wasm",
      instance.exports.getGlobal(),
      0,
    );
    global.value = 42;
    assertEq(
      "getting JS-updated value from wasm",
      instance.exports.getGlobal(),
      42,
    );
    instance.exports.incGlobal();
    assertEq("getting wasm-updated value from JS", global.value, 43);
  },
);
```

**Note**: GitHub에서 실행 중인 예제(running live on GitHub)를 볼 수 있습니다. source code도 참조하십시오.

명세서
---

| Specification |
| --- |
| WebAssembly JavaScript Interface # globals |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API
* Import/Export mutable globals proposal


WebAssembly.instantiateStreaming() - 웹어셈블리

WebAssembly.instantiateStreaming()
==================================

**`WebAssembly.instantiateStreaming()`** 함수는 스트림 된 원본 소스에서 직접 WebAssembly 모듈을 컴파일하고 인스턴스화합니다. Wasm 코드를로드하는 가장 효율적이고 최적화 된 방법입니다.

Syntax
------

```js
WebAssembly.instantiateStreaming(source, importObject);
```

### Parameters

*source*

스트리밍, 컴파일 및 인스턴스화하려는 .wasm 모듈의 기본 소스를 나타내는 `Response` 객체 또는 promise.

*importObject* Optional

함수 또는 `WebAssembly.Memory` 객체와 같이 새로 생성 된 `Instance`로 가져올 값을 포함하는 객체입니다. 컴파일 된 모듈의 각 선언 된 가져 오기에 대해 하나의 일치하는 속성이 있어야합니다. 그렇지 않으면 WebAssembly.LinkError가 발생합니다.

### Return value

두 개의 필드를 포함하는 `ResultObject`로 해석되는 `Promise` :

* `module`: 컴파일 된 WebAssembly 모듈을 나타내는 `WebAssembly.Module` 객체입니다. 이 `Module`은 다시 인스턴스화되거나 postMessage() (en-US)를 통해 공유 될 수 있습니다.
* `instance`: Exported WebAssembly functions를 포함하는 `WebAssembly.Instance` 객체입니다.
### Exceptions

* 매개 변수 중 하나가 올바른 유형 또는 구조가 아니면 `TypeError`가 발생합니다.
* 작업작업이 실패하면 promise는 실패 원인에 따라 `WebAssembly.CompileError`, `WebAssembly.LinkError` 또는 `WebAssembly.RuntimeError`로 거부됩니다.
Examples
--------

다음 예제 (GitHub의 instantiate-streaming.html 데모보기 및 view it live)에서는 원본 소스에서 .wasm 모듈을 직접 스트리밍 한 다음 컴파일하고 인스턴스화합니다. 약속은 `ResultObject`로 충족됩니다.`instantiateStreaming()` 함수는 `Response` 객체에 대한 promise를 받아들이므로 직접 `fetch()` 호출을 전달할 수 있으며 응답을 수행하면 함수에 응답을 전달합니다.

```js
var importObject = { imports: { imported\_func: (arg) => console.log(arg) } };

WebAssembly.instantiateStreaming(fetch("simple.wasm"), importObject).then(
  (obj) => obj.instance.exports.exported\_func(),
);
```

그런 다음 `ResultObject`의 인스턴스 구성원에 액세스하고 포함 된 내 보낸 함수를 호출합니다.

명세서
---

| Specification |
| --- |
| WebAssembly Web API # dom-webassembly-instantiatestreaming |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebAssembly overview page
* WebAssembly concepts
* Using the WebAssembly JavaScript API


Tutorials - 게임 개발

Tutorials
=========

이 페이지에는 다양한 형태의 웹 게임을 효과적으로 만들기 위해 중요한 여러가지 튜토리얼들을 포함하고 있습니다.

순수 JavaScript를 사용한 2D 게임 (en-US)

이 튜토리얼을 통해 여러분은 순수 JavaScript를 활용하여 간단한 게임을 만들어볼 수 있습니다. 렌더링, 이미지 그리기, 충돌 감지하기, 동작 원리, 승리/패배 구성하기 등 게임을 만들기 위해 필요한 기본적인 요소들을 구현하기 위해 `<canvas>` 사용법을 배우게 될 것입니다.

Phaser를 사용한 2D 게임 (en-US)

이 튜토리얼을 통해 여러분은 위 튜토리얼과 똑같은 게임을 만들어 볼 수 있을 것 입니다. 다만 이번에는 HTML5 게임 프레임워크인 Phaser를 이용하여 만들어 볼 것입니다. 게임을 만들기 위해 필요한 기본적인 요소들을 프레임워크를 활용하여 만드는 방법을 배우게 될 것입니다.

기기 수직/수평 기능을 이용한 2D 주사위 게임 (en-US)

이 튜토리얼에서는 `<canvas>` 가 제공하는 충돌 감지, 모양 놓기같은 기본적인 기능을 포함한 HTML5 2D 주사위 게임을 만들어 볼 것입니다. Device Orientation 기능과 Vibration (en-US) 기능을 활용한 모바일 게임이며 the Phaser프레임워크로 만들 것입니다.

Phaser를 사용한 2D 플랫폼 게임

이 튜토리얼 시리즈는 Phaser를 사용하여 스프라이트, 충돌, 물리학, 수집품 등과 같은 기본 사항을 다루는 간단한 플랫폼 게임을 만드는 방법을 보여줍니다.


웹 게임 개발에 대해 - 게임 개발

웹 게임 개발에 대해
===========

현대의 웹은 뛰어나고 고품질의 게임을 만들 뿐 만 아니라 이 게임들을 배급 하는 플랫폼으로 성장하였습니다.

제작되는 게임의 범위는 데스크탑이나 기본OS용 게임들에도 필적합니다다. 현대의 웹 기술과 최신 브라우저로 최고 사양의 웹 게임을 만드는게 가능해졌습니다. 우리는 예전에 Flash® 가지고 하던 가벼운 카드 게임이나 멀티플레이 소셜 게임을 말하는 게 아닙니다. 끝내주는 고사양의 3D 액션 슈팅 게임, RPG 게임, 그 이상을 말하는 것이죠. 자바 스크립트의 실시간 컴파일러 기술과 새로운 API의 대대적인 퍼포먼스 개선으로 이런게 가능해졌습니다. 브라우저로 (또는 HTML5를 사용하는 장비에서, 예시로 Firefox OS로 운영되는 장치에서 ) 운영되는 게임을 제작할 수 있게 되었습니다.

HTML5 게임 플랫폼
------------

우리는 웹을 우리의 게임에 더 좋은 타깃 플레폼이라고 생각합니다. 우리가 앞서 얘기했듯이 "웹이 곧 플랫폼이다." 라고 할 수 있죠. 아래의 웹 플랫폼의 핵심을 살펴보도록 합시다:

| 기능 | 기술 |
| --- | --- |
| **Audio (오디오)** | Web Audio API (en-US) |
| **Graphics (그래픽)** | WebGL (en-US) (OpenGL ES 2.0) |
| **Input (입력)** | Touch events (en-US), Gamepad API (en-US), device sensors, WebRTC (en-US), Full Screen API (en-US), Pointer Lock API (en-US) |
| **Language (언어)** | JavaScript (or C/C++ using Emscripten to compile to JavaScript) |
| **Networking (네트워킹)** | WebRTC (en-US) and/or WebSockets |
| **Storage (저장공간)** | IndexedDB or the "cloud" |
| **Web (웹)** | HTML, CSS, SVG, Social API (and much more!) |

비즈니스 예시
-------

개인이든 대형 게임 제작사든 게임 개발자라면, 당신의 다음 게임 개발 프로젝트로 왜 웹을 타킷으로 설정해야 하는지 알고 싶을 것입니다. 웹이 어떻게 당신에게 도움이 될 수 있는지 알아봅시다:

1. 웹의 범위는 방대하죠. 어디에든 있습니다. HTML5로 만들어진 게임은 스마트폰, 태블릿, PC, 심지어 스마트 TV에서도 작동합니다.
2. 마케팅과 검색 가능성이 향상되었습니다. 다른 앱 스토어에만 국한되지 않고 어느 곳에서나 당신의 앱을 홍보할 수 있습니다. 웹 고유 특성인 링크와 공유 덕분에 새로운 고객에게 전세계 웹은 물론 다른 미디어에서도 광고나 홍보가 가능합니다.
3. 가장 중요한것을 당신이 관리 할 수 있습니다: 바로 결제 시스템 입니다 . 당신의 게임이 다른 이의 앱 생태계에 들어있다는 이유만으로 수익의 30%를 넘겨주지 않아도 됩니다. 대신, 당신이 원하는 만큼 가격을 책정하고 원하는 결제 방식을 사용할 수 있죠.
4. 당신이 관리 할 수 있는 더 중요한 부분이 있습니다. 당신이 원할 때 게임을 업데이트할 수 있다는 것입니다. 다른 회사의 누군가가 버그 수정을 오늘 올릴지, 내일 올릴지 결정하는 것을 숨 막히게 기다리지 않아도 됩니다.
5. 게임에 대한 분석을 관리할 수 있다. 당신이 필요한 분석 자료에 대해 다른 누군가에게 의존하지 않아도 된다. 매출이나 게임의 영향력에 대한 정보를 모으기 위해 당신 스스로 분석 자료를 수집하거나 선호하는 서드파티를 선택할 수 있다.
6. 고객 관계를 보다 면밀하게 관리 할 수 있습니다. 고객 피드백을 앱 스토어의 제한된 방식을 통해 받지 않아도 됩니다. 중매인이 없이 원하는 방식으로 고객과 소통하십시오. [주의: 현재 번역이 완벽하지 않습니다]
7. 게임 플레이어들이 어디서든, 언제든지 당신의 게임을 할 수 있다. 웹이 보편적이기 때문에, 당신의 고객들은 그들의 게임 현황을 폰에서든, 타플렛에서든, 랩탑에서든, 업무용 데스크탑에서든, 혹은 어디서든 확인할 수 있다.
게임 개발자들을 위한 웹 기술
----------------

게임개발을 하는 우리의 개발자 친구들을 위해 게임을 실현케 하는 몇가지 API들을 알아봅시다. 여기에 웹으로 할 수 있는 간략한 리스트를 보여드리겠습니다:

Full Screen API (en-US)

이 간단한 API는 당신의 게임이 스크린 전체를 차지하도록 하여 플레이어가 집중하도록 도와줍니다.

Gamepad API (en-US)

당신 게임의 유저가 게임패드를 사용 가능하기를 원한다면, 아니면 다른 게임 컨트롤러를 게임에 적용시키고자 한다면 이 API가 필요할 것 입니다.

HTML and CSS

이 두 기술이 게임 개발, 스타일, 레이아웃, 유저 인터페이스를 가능하게 할것입니다. HTML중 `<canvas>` 부분은 2D 그래픽을 가능하게 하는 방법중 하나입니다.

HTML audio (en-US)

`<audio>` (en-US) 는 쉽게 간단한 음향 효과나 음악을 가능하게 해줍니다. 이보다 더 한 음향 효과를 필요로 한다면 제대로된 오디오 프로세싱 파워를 가진 Web Audio API (en-US) 를 확인해 보세요!

IndexedDB

사용자 데이터를 사용자 기기에 저장시키는 강력한 데이터 저장 API 입니다. 로컬데이터로 저장하여 매번 다운로드 받을 필요 없이 게임 state와 다른 정보들 필요할 때 마다 저장 할 수 있습니다. 또한 당신의 게임이 오프라인 상에서도 실행이 가능하도록 하는데 도움이 됩니다. ( 유저가 비행모드 일 때 등등 말이죠)

JavaScript

JavaScript, 웹 개발에 사용되는 언어, 이는 최신 브라우저에서 아주 빠르고 매번 더욱 빨라지고 있습니다. 이 강력한 언어를 당신의 게임을 위해 사용 해보시고, 현재 이미 만들어진 게임에 Emscripten 혹은 Asm.js 과같은 기술들을 사용해보세요.

Pointer Lock API (en-US)

The Pointer Lock API lets you lock the mouse or other pointing device within your game's interface so that instead of absolute cursor positioning you receive coordinate deltas that give you more precise measurements of what the user is doing, and prevent the user from accidentally sending their input somewhere else, thereby missing important action.

SVG (Scalable Vector Graphics)

Lets you build vector graphics that scale smoothly regardless of the size or resolution of the user's display.

Typed Arrays (en-US)

JavaScript typed arrays give you access to raw binary data from within JavaScript; this lets you manipulate GL textures, game data, or anything else, even if it's not in a native JavaScript format.

Web Audio API (en-US)

This API for controlling the playback, synthesis, and manipulation of audio from JavaScript code lets you create awesome sound effects as well as play and manipulate music in real time.

WebGL (en-US)

Lets you create high-performance, hardware-accelerated 3D (and 2D) graphics from Web content. This is a Web-supported implementation of OpenGL ES 2.0.

WebRTC (en-US)

The WebRTC (Real-Time Communications) API gives you the power to control audio and video data, including teleconferencing and transmitting other application data back and forth between two users. Want your players to be able to talk to each other while blowing up monsters? This is the API for you.

WebSockets

The WebSocket API lets you connect your app or site to a server to transmit data back and forth in real-time. Perfect for multiplayer gaming action, chat services, and so forth.

Web Workers (en-US)

Workers give you the ability to spawn background threads running their own JavaScript code, to take advantage of modern, multi-core processors.

XMLHttpRequest (en-US) and File API

The combination of XMLHttpRequest and the File API lets you send and receive any kind of data you want (don't let the "XML" throw you!) from a Web server. This is a great way to do anything from downloading new game levels and artwork to transmitting non-real-time game status information back and forth.


순수한 자바스크립트를 이용한 2D 벽돌깨기 게임 - 게임 개발

순수한 자바스크립트를 이용한 2D 벽돌깨기 게임
==========================

* 다음 »

이 튜토리얼을 차례차례 진행하면서 우리는 HTML5 `<canvas>` 로 렌더되는 순수하게 JavaScript로만 쓰여진 간단한 **MDN 벽돌깨기** 게임을 만들 것입니다.

모든 과정은 플레이 가능하고 편집가능한 라이브 샘플을 포함하고 있습니다. 이 샘플을 통해, 여러분은 중간 스테이지들이 어떻게 보여져야 하는지 확인할 수 있습니다. 여러분은 이미지의 렌더링과 움직임, 충돌 감지, 컨트롤 메카니즘들과 승리와 패배 상태와 같은 기본적인 게임 원리들을 구현하기 위해서, `<canvas>`엘리먼트의 기본적인 사용 방법을 배우게 될 것입니다.

이 시리즈를 최대한 활용하려면 중급의 JavaScript 지식이 있어야 합니다. 이 튜토리얼을 끝낸 후에는 여러분은 스스로 간단한 웹 게임들을 만들 수 있게 될 것입니다.

![Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.](/ko/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/mdn-breakout-gameplay.png)

강의 내용
-----

모든 강의 내용과 우리가 함께 만드는 MDN 벽돌깨기 게임의 다른 버전들은 GitHub에서 찾을 수 있습니다.:

1. 캔버스 생성과 그리기
2. 공 움직이기 (en-US)
3. 벽으로 부터 튕겨나오기 (en-US)
4. 패들과 키보드 컨트롤 (en-US)
5. 게임 오버 (en-US)
6. 벽돌 필드 만들기 (en-US)
7. 충돌 감지 (en-US)
8. 점수 추적과 승리 (en-US)
9. 마우스 컨트롤 (en-US)
10. 마무리 (en-US)

웹 게임 개발의 확고한 지식을 얻기 위한 최고의 방법은 순수하게 JavaScript만 이용해서 시작하는 것입니다. 이후에, 여러분은 프로젝트에 프레임워크를 골라서 사용할 수도 있습니다. 프레임워크들은 JavaScript로 만들어진 도구일 뿐입니다. 따라서 여러분이 프레임워크를 사용하더라도, 프레임워크 밑에서 정확히 어떤 일이 일어나는지 알기 위해 언어를 배우는것이 좋습니다. 프레임워크들은 개발 속도를 올려주고, 게임의 지루한 부분들을 해결하는데 도움을 줍니다. 하지만 어떤 일들이 기대한대로 일어나지 않는다면, 여러분은 디버그를 시도하거나 여러분 스스로 순수하게 JavaScript만 이용한 솔루션을 작성할 수 도 있습니다.

**참고:** 만약 여러분이 게임 라이브러리를 이용한 2D 웹 게임 개발의 학습에 흥미가 있다면, 이 시리즈의 대응 파트인 2D breakout game using Phaser (en-US)를 살펴보시기 바랍니다.

**참고:** 이 시리즈의 내용들은 게임개발 워크숍의 재료로 쓰일 수 있습니다. 또한, 만약 여러분이 게임개발에 있어 강연을 원한다면 이 튜토리얼에 기초한 Gamedev Canvas Content Kit를 활용할 수 있습니다.

다음 단계
-----

좋습니다, 이제 시작하도록 합시다. 첫 번째 챕터인 캔버스 생성과 그리기 부터 시작합니다.

* 다음 »


2D breakout game using Phaser - 게임 개발

2D breakout game using Phaser
=============================

* 다음 »

이 튜토리얼을 차례차례 진행하면서 우리는 HTML5 `<canvas>` 로 렌더되는 순수한 JavaScript로 쓰여진 간단한 MDN 벽돌깨기 게임을 만들 것입니다.

모든 과정은 플레이 가능하고 편집가능한 라이브 샘플을 포함하고 있습니다. 이 샘플을 통해, 여러분은 중간 스테이지들이 어떻게 보여져야 하는지 확인할 수 있습니다. 여러분은 이미지의 렌더링과 움직임, 충돌 감지, 컨트롤 메카니즘들과 승리와 패배 상태와 같은 기본적인 게임 원리들을 구현하기 위해서, `<canvas>`엘리먼트의 기본적인 사용 방법을 배우게 될 것입니다.

이 시리즈를 최대한 활용하려면 중급의 JavaScript 지식이 있어야 합니다. 이 튜토리얼을 끝낸 후에는 여러분은 스스로 간단한 웹 게임들을 만들 수 있게 될 것입니다.

![Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.](/ko/docs/Games/Tutorials/2D_breakout_game_Phaser/mdn-breakout-gameplay.png)

강의 내용
-----

모든 강의 내용과 우리가 함께 만드는 MDN 벽돌깨기 게임의 다른 버전들은 GitHub에서 찾을 수 있습니다.:

1. 캔버스 생성과 그리기
2. 공 움직이기 (en-US)
3. 벽으로 부터 튕겨나오기 (en-US)
4. 패들과 키보드 컨트롤 (en-US)
5. 게임 오버 (en-US)
6. 벽돌 필드 만들기 (en-US)
7. 충돌 감지 (en-US)
8. 점수 추적과 승리 (en-US)
9. 마우스 컨트롤 (en-US)
10. 마무리 (en-US)

웹 게임 개발의 확고한 지식을 얻기 위해 순수한 JavaScript로 시작하는 것은 최고의 방법입니다. 이후에, 여러분은 프로젝트에 프레임워크를 골라서 사용할 수도 있습니다. 프레임워크들은 JavaScript로 만들어진 툴일 뿐입니다. 따라서 여러분이 프레임워크를 사용하더라도, 프레임워크 밑에서 정확히 어떤 일이 어떤일이 일어나는지 알기 위해 언어를 배우는것은 좋은 일입니다. 프레임워크들은 개발 속도를 올려주고, 게임의 지루한 부분들을 해결하는데 도움을 줍니다. 하지만 어떤 일들이 기대한대로 일어나지 않는다면, 여러분은 디버그를 시도하거나 여러분 스스로 순수한 JavaScript로 솔루션을 작성할 수 도 있습니다.

**참고:** 만약 여러분이 게임 라이브러리를 이용한 2D 웹 게임 개발의 학습에 흥미가 있다면, 이 시리즈의 대응 파트인 2D breakout game using Phaser (en-US)를 살펴보시기 바랍니다.

**참고:** 이 시리즈의 내용들은 게임개발 워크숍의 재료로 쓰일 수 있습니다. 또한, 만약 여러분이 게임개발에 있어 강연을 원한다면 이 튜토리얼에 기초한 Gamedev Canvas Content Kit를 활용할 수 있습니다.

다음 단계
-----

좋습니다, 이제 시작하도록 합시다. 첫 번째 챕터인 캔버스 생성과 그리기 부터 시작합니다.

* 다음 »


득점 - 게임 개발

득점
==

* « 이전 (en-US)
* 다음 » (en-US)

이것은 Gamedev Phaser tutorial (en-US)의 16단계중 11번째 과정입니다. 이 과정의 소스코드를 얻고자 한다면 이 강좌를 수강한 후 Gamedev-Phaser-Content-Kit/demos/lesson11.html를 통해 얻으세요.

점수를 얻는 방식의 게임은 좀더 재미있을 것 입니다.— 당신 또는, 친구의 최고 기록을 갈아치울수도 있습니다. 이 글에서는 우리의 게임에 득점 시스템을 추가해 보려고 합니다.

우리는 점수를 저장해두기 위해 여러 변수를 사용하고, 점수를 화면에 출력하기 위해 내부의 `text()` 메서드를 사용합니다.

새로운 변수들
-------

이전 정의되었던 변수들 바로 다음에 다음과 같이 새로운 변수 두개를 추가해 주세요:

```js
// …
let scoreText;
let score = 0;
```

게임 화면에 점수가 표시 되도록 해보자
---------------------

`지금 create()` 함수 뒤에 다음과 같은 코드를 추가해봅시다:

```js
scoreText = game.add.text(5, 5, "Points: 0", {
  font: "18px Arial",
  fill: "#0095DD",
});
```

`text()` 메소드는 4개의 변수를 가질수 있습니다:

* x와 y 좌표값 자리에 글자를 그려냅니다.
* 실제 글자가 나타날 것입니다.
* 폰트도 글자와 함께 나타날 것입니다.

마지막 변수는 CSS와 매우 비슷해 보입니다. 우리의 점수는 파란색에, 18픽셀 크기이며, Arial 폰트를 사용하여 나타날 것입니다.

블록이 무너지면 점수를 갱신합니다
------------------

우리는 공이 블록을 칠때마다 점수를 증가시킵니다 그리고 공이 블록을 칠때마다 동시에 점수판을 갱신하여 화면에 현재 점수를 나타낼 것입니다. 이건 `setText()매소드를 써서 해결 할수 있습니다` — `ballHitBrick()` 함수 아래로 다음과 같은 새로운 코드 두 줄을 추가하세요:

```js
function ballHitBrick(ball, brick) {
  brick.kill();
  score += 10;
  scoreText.setText(`Points: ${score}`);
}
```

됐습니다, — `index.html` 을 다시 새로고침 해주고 공이 블록을 칠때마다 점수가 갱신되는지 확인해줍니다.

코드를 비교해보세요
----------

이번 강좌에서 배운 득점 시스템이 어떻게 작동하는지 이해하고자 한다면, 다음 아래를 이용해 시연해보세요.:

다음 단계
-----

우리는 이제 득점 시스템을 게임에 추가했습니다. 그러나 게임에서 이길 수 없다면, 게임하면서 득점하는게 무슨 소용일까요? 그래서 승리 상태를 추가해보려고 합니다. 게임에서 이기게 하고 싶다면 다음으로 넘어갑시다: win the game (en-US).

* « 이전 (en-US)
* 다음 » (en-US)


Paddle과 키보드 컨트롤 - 게임 개발

Paddle과 키보드 컨트롤
===============

* « 이전
* 다음 »

이 글은 Gamedev Canvas tutorial (en-US)의 10단계 중 4단계 입니다. 이 글을 다 읽고 난 뒤 완성된 소스코드는 Gamedev-Canvas-workshop/lesson4.html 에서 확인할 수 있습니다.

공이 계속해서 벽을 튕기며 이동하는 모습을 볼 수 있지만, 현재로서는 그것을 컨트롤 할 방법이 없습니다. 컨트롤 할 수 없으면 게임이 아니죠! paddle을 컨트롤 할 수 있는 몇가지 상호작용을 추가해 봅시다.

공을 치기 위한 paddle 정의
------------------

먼저, 우리는 공을 치기 위한 paddle이 필요합니다. 이를 위해 몇가지 변수들을 정의합시다. 코드 상단에 다른 변수들과 함께 아래 변수들을 추가하세요:

```js
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width - paddleWidth) / 2;
```

여기에서 paddle의 높이와 너비, 그리고 `x` 축 위에 시작 지점을 정의합니다. paddle을 스크린에 그리는 함수를 만듭시다. `drawBall()` 함수 아래에 다음 코드를 추가하세요:

```js
function drawPaddle() {
  ctx.beginPath();
  ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}
```

유저의 paddle 컨트롤
--------------

paddle은 우리가 원하는 곳 어디든 그릴 수 있지만, 사용자의 컨트롤에 반응해야 합니다. — 키보드 컨트롤을 구현합시다. 다음 내용이 필요합니다.:

* 왼쪽 혹은 오른쪽 컨트롤 버튼이 눌렸는지 확인하는 두개의 변수
* `keydown` 과 `keyup` 이벤트 리스너 — 버튼이 눌렸을 때 paddle의 움직임을 조종할 수 있는 코드가 실행되어야 합니다.
* 버튼이 눌렸을 때 `keydown` 과 `keyup` 이벤트를 핸들링하는 두개의 함수
* paddle이 왼쪽 혹은 오른쪽으로 움직이는 기능

버튼을 누르는 것은 boolean 변수로 정의하고 초기화 합니다. 아래 코드를 변수 선언 부분에 추가하세요. :

```js
var rightPressed = false;
var leftPressed = false;
```

처음에는 컨트롤 버튼이 눌려지지 않은 상태이므로 두개의 기본값은 false 입니다. 키가 눌렸음을 인식하기 위해, 이벤트 리스너를 설정합니다. JavaScript 하단에 `setInterval()` 바로 위에 아래 코드를 추가합니다.:

```js
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
```

키보드 중 어떤 키 하나가 눌려서 `keydown` 이벤트가 발생하면, `keyDownHandler()` 함수가 실행됩니다. 두번째 리스너에도 같은 패턴이 적용됩니다: 키에서 손을 때면 `keyup` 이벤트가 `keyUpHandler()` 함수를 실행합니다 . `addEventListener()` 아래에 다음 코드를 추가하세요:

```js
function keyDownHandler(e) {
  if (e.keyCode == 39) {
    rightPressed = true;
  } else if (e.keyCode == 37) {
    leftPressed = true;
  }
}

function keyUpHandler(e) {
  if (e.keyCode == 39) {
    rightPressed = false;
  } else if (e.keyCode == 37) {
    leftPressed = false;
  }
}
```

키를 누르면 변수에 정보가 저장됩니다. 각 경우에 관련된 변수가 `true` 로 설정됩니다. 키에서 손을 때면, 변수값은 `false`로 되돌아갑니다.

두 함수 모두 e 변수로 표시되는 이벤트를 파라미터로 사용합니다. 이것으로 유용한 정보를 얻을 수 있습니다: `keyCode` 는 눌려진 키에 대한 정보를 가지고 있습니다. 예를 들어 키 코드 37 은 왼쪽 방향키이고 39 는 오른쪽 방향키 입니다. 만약에 왼쪽 방향키를 누르면, `leftPressed` 변수가 `true` 로 설정되고, 왼쪽 방향키에서 손을 때면 `leftPressed` 변수가 `false`로 설정됩니다. 오른쪽 방향키와 `rightPressed` 변수에도 동일한 패턴이 적용됩니다.

### Paddle 이동 로직

이제 우리는 눌려진 키, 이벤트 리스너, 관련된 함수에 대한 정보를 저장할 변수를 가지고 있습니다. 이제 실제 코드를 사용하여 이것들을 사용하고 paddle을 화면에서 움직여봅시다. `draw()` 함수에서, 각각의 프레임이 렌더링 될때마다 왼쪽이나 오른쪽 방향키가 눌려졌는지 확인합니다. 코드는 아래와 같습니다:

```js
if (rightPressed) {
  paddleX += 7;
} else if (leftPressed) {
  paddleX -= 7;
}
```

만약 왼쪽 방향키를 누르면, paddle은 좌측으로 7픽셀 움직이고, 오른쪽 방향키를 누르면, 우측으로 7픽셀 움직입니다. 잘 작동하지만, 키를 너무 오래 누르고 있으면 paddle이 캔버스 밖으로 사라집니다. 아래처럼 코드를 수정해서 paddle이 캔버스 안에서만 움직이도록 개선합니다:

```js
if (rightPressed && paddleX < canvas.width - paddleWidth) {
  paddleX += 7;
} else if (leftPressed && paddleX > 0) {
  paddleX -= 7;
}
```

`paddleX` 의 위치는 캔버스 왼쪽 끝 `0` 위치와 오른쪽 `canvas.width-paddleWidth` 에서 움직입니다.

위의 코드를 `draw()` 함수 아래쪽에 추가합니다.

이제 paddle이 화면에서 실제로 그려지도록 `draw()` 함수 안에서 `drawPaddle()` 을 호출합니다. `draw()` 함수 안에 `drawBall()` 아래에 다음 코드를 추가합니다:

```js
drawPaddle();
```

여러분의 코드와 비교해보세요
---------------

여기 움직이는 코드를 확인해보세요:

**참고:** **Exercise**: paddle의 움직임을 빠르거나 느리게, 혹은 사이즈를 변경해보세요.

다음 단계
-----

게임과 비슷해지긴 했지만 한가지 문제는 게임이 끝나지 않는다는 것입니다. 5단계에서 Game over (en-US)를 추가할 것입니다.

* « 이전
* 다음 »


개발 마무리 - 게임 개발

개발 마무리
======

* « 이전

Gamedev Canvas tutorial의 **10개의 레슨 중 마지막 단계**입니다. 이 수업을 마친 후 비교하여 살펴볼 소스코드는 Gamedev-Canvas-workshop/lesson10.html에서 찾아볼 수 있습니다.

우리가 쓰는 모든 게임에 항상 개선해야 할 것이 있습니다. 예를 들자면, 우리는 플레이어에게 한 개보다 많은 라이프를 제공할 수 있습니다. 플레이어들은 한 번 또는 두 번의 실수를 만들어도 여전히 게임을 끝낼 수 있습니다. 우리는 또한 우리의 코드 렌더링을 개선할 수 있습니다.

플레이어에게 생명을 부여하기
---------------

생명을 구현하는 방법은 아주 간단합니다. 먼저 변수를 선언했던 곳과 같은 장소에서 변수를 추가하여 생명 수를 저장합니다.

```js
let lives = 3;
```

남은 생명 수를 표시하는 방법은 점수 카운터가 그려지는 것과 같은 형태입니다. `drawScore()`함수 아래에 다음 기능을 추가하세요.

```js
function drawLives() {
  ctx.font = "16px Arial";
  ctx.fillStyle = "#0095DD";
  ctx.fillText(`Lives: ${lives}`, canvas.width - 65, 20);
}
```

지금까지 바닥에 닿으면 바로 게임을 끝내는 형식이었습니다. 이제 우리는 더 이상 게임을 이용할 수 없게 될 때까지 남은 생명 수를 줄일 것입니다. 또한 플레이어가 게임 오버되면 다시 생명과 블럭들을 리셋하여 공과 패들 위치를 재설정할 수 있습니다. 그렇게 하기 위해 `draw()` 함수 내에서 다음 세 줄을 다음 블럭의 코드로 대체합시다.

```js
alert("GAME OVER");
document.location.reload();
clearInterval(interval); // Needed for Chrome to end game
```

이를 통해 아래와 같이 약간 복잡한 논리를 추가할 수 있습니다:

```js
lives--;
if (!lives) {
  alert("GAME OVER");
  document.location.reload();
  clearInterval(interval); // Needed for Chrome to end game
} else {
  x = canvas.width / 2;
  y = canvas.height - 30;
  dx = 2;
  dy = -2;
  paddleX = (canvas.width - paddleWidth) / 2;
}
```

자, 이제 공이 화면의 맨 아래 가장자리에 맞으면 생명(`lives`)을 하나 뺍니다. 생명이 없다면 게임이 끝나고 아직 남아있다면 공의 위치와 패들의 위치가 재설정 됩니다.

### 남은 생명 표시 렌더링하기

이제 `draw()`함수 내에서 `drawLives()`에 생명 수를 추가하고 `drawLives()` 아래에 생명 수를 추가해야 합니다.

```js
drawLives();
```

requestAnimationFrame()을 사용하여 랜더링 개선하기
--------------------------------------

이제 게임 메커니즘과 연결이 되지 않지만, 그것이 렌더링되는 방식에 대해 연구해 봅시다. `requestAnimationFrame`은 우리가 현재 `setInterval()` (en-US)을 사용하여 구현한 고정된 프레임레이트(fixed framerate)보다 더 낫게 게임을 렌더링합니다. 다음 줄을,

```js
const interval = setInterval(draw, 10);
```

이렇게 대체하세요.

```js
draw();
```

다음 각 인스턴스를 제거합니다:

```js
clearInterval(interval); // Needed for Chrome to end game
```

그 다음, `draw()`함수의 맨 아래 (닫는 '`}`'바로 전에) 다음 줄을 추가하여 `draw()`함수가 반복적으로 자신을 호출하게 합니다:

```js
requestAnimationFrame(draw);
```

이 `draw()` 함수는 현재 `requestAnimationFrame()` 루프 내에서 반복적으로 실행되고 있지만, 고정된 10ms 프레임 대신 프레임의 제어권을 브라우저에 다시 부여 합니다. 이는 프레임과 적절하게 일치하고 필요할 때만 모양을 만들 것입니다. 이것은 이전의 `setInterval()` 방법보다 더 효율적이고 부드럽게 애니메이션 루프를 만듭니다.

코드 비교하기
-------

그것이 이 레슨의 전부입니다. 게임의 최종 버전이 준비되어 있고 시작할 준비가 되어 있습니다!

**참고:** 생명의 수와 공이 패들에서 튕겨나가는 각도를 변경해 보세요.

게임 오버 - 마무리!
------------

축하합니다! 당신은 모든 수업을 완수하였습니다! 이쯤 되면 이제 캔버스의 조작 기초와 간단한 2D 게임 구현 방법을 알게 되었을 것입니다. 이제 몇몇 프레임워크를 배우고 게임 개발을 계속하기에 좋은 시간입니다. 이 시리즈의 2D breakout game using Phaser 또는 Cyber Orb built in Phaser (en-US) 튜토리얼을 확인해 볼 수 있습니다. Games section on MDN의 섹션에서 더 많은 지식과 영감을 얻어보세요.

당신은 또한 이 튜토리얼 시리즈의 메인 페이지로 돌아갈 수 있습니다. 즐겁게 코딩하세요!

* « 이전


벽돌 만들기 - 게임 개발

벽돌 만들기
======

* « 이전
* 다음 »

이번 단계는 Gamedev Canvas tutorial (en-US)의 여섯 번째 학습입니다. Gamedev-Canvas-workshop/lesson6.html에서 이번 학습의 소스코드를 확인할 수 있습니다.

게임플레이 원리를 수정한 후에, 우리는 게임에서 패배할 수 있게 되었습니다. 이것은 실제 게임에 보다 가까운 느낌이기 때문에 훌륭합니다. 하지만 벽과 패들에 공이 튀기는 것 말고 할 수 있는 것이 없기 때문에 금방 지루해집니다. 벽돌깨기 게임에서 진정으로 필요로 한 것은 공으로 파괴할 벽돌입니다. 이 것이 지금 우리가 만들 것입니다!

벽돌에 대한 변수 설정하기
--------------

이번 학습의 모든 목표는 벽돌들을 위한 코드를 2차원 배열로 동작하는 반복문을 통해 제공하는 것입니다. 그러나 먼저 우리는 가로, 세로, 행, 열 등 벽돌에 대한 값을 정의할 몇몇 변수들을 설정해야 합니다. 지난 학습에서 작성한 코드에 아래 코드를 추가해봅시다.

```js
const brickRowCount = 3;
const brickColumnCount = 5;
const brickWidth = 75;
const brickHeight = 20;
const brickPadding = 10;
const brickOffsetTop = 30;
const brickOffsetLeft = 30;
```

우리는 벽돌 배열 행과 열의 수, 그것들의 가로, 세로길이, 각 벽돌이 서로 닿지 않을 정도의 간격과 벽돌이 캔버스의 모서리에 닿지 않게 할 오프셋 변수들을 정의했습니다.

우리는 2차원 배열에 벽돌을 담았습니다. 배열은 열 `c`, 행 `r`, 그리고 배열의 각 객체엔 화면에 벽돌을 그릴 위치를 나타낼 `x`, `y` 위치를 가지고 있습니다. 위에서 변수를 선언한 코드 뒤에 아래 코드를 추가해봅시다.

```js
const bricks = [];
for (let c = 0; c < brickColumnCount; c++) {
  bricks[c] = [];
  for (let r = 0; r < brickRowCount; r++) {
    bricks[c][r] = { x: 0, y: 0 };
  }
}
```

위 코드는 행과 열 수만큼 반복되면서 새로운 벽돌을 만듭니다. 각 벽돌 객체는 이후에 충돌감지에 사용됩니다.

벽돌을 그리는 방법
----------

이제 배열안의 모든 벽돌을 반복해서 화면에 그려줄 함수를 만들어봅시다. 코드는 아래와 같습니다.

```js
function drawBricks() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      bricks[c][r].x = 0;
      bricks[c][r].y = 0;
      ctx.beginPath();
      ctx.rect(0, 0, brickWidth, brickHeight);
      ctx.fillStyle = "#0095DD";
      ctx.fill();
      ctx.closePath();
    }
  }
}
```

다시 행, 열 반복을 통해 각 벽돌의 `x`, `y` 값을 설정하고, 캔버스에 `brickWidth` \* `brickHeight` 크기의 벽돌들을 그립니다. 문제는 모든 벽돌들이 좌표 (0, 0) 위치해있다는 것입니다. 우리는 약간의 연산을 통해 각 벽돌의 `x`, `y` 값을 계산해야 합니다.

```js
const brickX = c \* (brickWidth + brickPadding) + brickOffsetLeft;
const brickY = r \* (brickHeight + brickPadding) + brickOffsetTop;
```

`brickX`는 `brickWidth` + `brickPadding`에 `c`를 곱하고, `brickOffsetLeft`를 더한 값입니다. `brickY`는 변수 `r`, `brickHeight`, `brickOffsetTop` 변수를 사용한다는 것을 제외하곤 동일합니다. 이제 모든 벽돌들을 올바른 위치에, 알맞은 간격을 두고, 캔버스 모서리로부터 오프셋 값만큼의 거리를 둔 상태로 그릴수 있게되었습니다.

`brickX`와 `brickY` 값을 (0, 0) 대신에 좌표 값으로 할당한 후에 `drawBricks` 함수의 마지막 버전은 아래와 같을 것입니다. 이 코드는 `drawpaddle` 함수 아래에 추가해봅시다.

```js
function drawBricks() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      const brickX = c \* (brickWidth + brickPadding) + brickOffsetLeft;
      const brickY = r \* (brickHeight + brickPadding) + brickOffsetTop;
      bricks[c][r].x = brickX;
      bricks[c][r].y = brickY;
      ctx.beginPath();
      ctx.rect(brickX, brickY, brickWidth, brickHeight);
      ctx.fillStyle = "#0095DD";
      ctx.fill();
      ctx.closePath();
    }
  }
}
```

실제 벽돌을 그리기
----------

이 학습에서 마지막으로 할 일은 `drawBrick`함수를 호출하는 코드를 `draw`함수 어딘가에, 되도록이면 시작하는 부분에, 캔버스를 초기화하는 부분과 공을 그리는 사이에 추가하는 것입니다. 아래 코드를 `drawBall()` 코드 위에 추가해봅시다.

```js
drawBricks();
```

코드 비교해보기
--------

이 부분에서 게임은 조금 더 흥미로워졌습니다.

**참고:** 연습하기: 행과 열의 수를 바꿔서 벽돌의 수를 변경해보거나, 위치를 변경해봅시다.

다음 단계
-----

이제 우리에겐 벽돌이 있습니다! 하지만 공은 벽돌들과의 반응이 없습니다. 우리는 다음 단계에서 이 문제에 대해 다룰 것입니다: 충돌 감지

* « 이전
* 다음 »


공 움직이기 - 게임 개발

공 움직이기
======

* « 이전
* 다음 »

이 강의는 게임 개발 캔버스 튜토리얼 (en-US)의 10단계 중 두 번째 과정입니다. Gamedev-Canvas-workshop/lesson2.html에서 이 강의의 완성된 코드를 볼 수 있습니다.

여러분은 이전 과정에서 어떻게 공이 그려지는지 배웠습니다. 이젠 공을 움직이게 만들어보죠! 기술적으로는 화면에 공을 그렸다가 지우는 과정을 반복하게 되는데, 매 프레임마다 공의 위치를 조금씩 다르게 해서 그리면 공이 움직이는것 처럼 보이게 됩니다. 마치 영화 화면이 움직이는 방식처럼 말이죠!

드로잉 루프를 정의하기
------------

매 프레임마다 캔버스에 그리는것을 지속적으로 갱신하기 위해서는, 계속해서 그리는 것을 반복하게 만들어주는 함수가 필요합니다. 이 함수는 매 프레임마다 위치를 바꿔주기 위한 몇가지 변수들을 포함합니다. JavaScript 타이밍 함수인 `setInterval()` (en-US)나 `requestAnimationFrame()`를 이용하면 함수를 몇번이고 계속 반복해서 실행할 수 있습니다..

현재 여러분의 HTML파일 안에 있는 JavaScript중에 처음 두 줄만 제외하고 나머지는 모두 지워주세요. 지운 후에는 아래에 있는 코드를 추가해주세요. `draw()`함수는 `setInterval`를 통해서 10밀리초마다 실행됩니다.

```js
function draw() {
  // drawing code
}
setInterval(draw, 10);
```

무한히 작동하는 `setInterval` 함수 덕에, `draw()` 함수는 우리가 멈추기 전 까지 10밀리초마다 영원히 호출됩니다. 이제 공을 그려봅시다! 다음 코드를 여러분의 `draw()` 함수 안에 추가해주세요.

```js
ctx.beginPath();
ctx.arc(50, 50, 10, 0, Math.PI \* 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
```

이제 바뀐 코드를 실행해 보세요. 공은 매 프레임마다 다시 그려지게 됩니다.

움직이게 만들기
--------

공이 움직이지 않고 있기 때문에, 여러분은 공이 다시 그려지고 있다는 사실을 알아챌 수 는 없었을 것입니다. 이제 공을 움직이게 바꿔봅시다. 첫 번째로, (50,50)이라는 지정된 좌표 대신에, x와 y라는 변수를 이용해서 화면 하단 중앙에서 그려지도록 하겠습니다.

x와 y를 정의하기 위해서 다음 두 줄을 여러분의 `draw()` 함수위에 추가해주세요.

```js
let x = canvas.width / 2;
let y = canvas.height - 30;
```

그 다음에는 `draw()` 함수를 갱신할 것입니다. 아래 코드에서 강조된 줄에서 처럼, `arc()` (en-US)메소드안에서 x와 y 변수를 사용하게 됩니다.

```js
function draw() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI \* 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}
```

이제 중요한 부분입니다. 공을 움직이는 것을 표현하기 위해 x와 y에 작은 값을 매 프레임마다 더해줄 것입니다. 그 작은 값을 dx와 dy라 정의하고, 각각 2와 -2로 그 값을 정해보겠습니다. 다음 코드를 여러분의 x와 y변수가 정의된 코드 아래에 추가하세요.

```js
let dx = 2;
let dy = -2;
```

마지막으로 할 일은 dx와 dy변수를 이용해서 매 프레임마다 x와 y변수를 갱신해 주는 것입니다. 그렇게 하면 매 갱신마다 공은 새 위치에 그려지게 됩니다. 다음 코드에 표시된 새로운 두 줄의 코드를 여러분의 `draw()` 함수에 추가해주세요.

```js
function draw() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI \* 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}
```

여러분의 코드를 다시 저장하고, 브라우저를 열어 실행해보세요. 공은 잘 움직이는군요. 뒤에 흔적이 남기는 하지만 말이죠.

![A blue line that indicates where the ball has been](/ko/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball/ball-trail.png)

다음 프레임 전에 캔버스를 지우기
------------------

공이 흔적을 남기는 것은, 매 프레임마다 공을 그릴 때 이전 프레임을 지워주지 않았기 때문입니다. 하지만 걱정할 것은 없습니다. 캔버스의 내용들을 지워주기 위한 메소드인 `clearRect()` (en-US)가 있으니까요. 이 메소드는 네 개의 파라미터가 필요합니다. 직사각형의 좌상단 모서리를 표시할 x와 y좌표, 그리고 직사각형의 우하단 모서리를 표시할 x와 y좌표가 바로 그것이죠. 이 좌표들로 생기는 사각형 안에 있는 것들은 전부 지워지게 될 것입니다.

다음 코드에서 강조된 새로운 한줄의 코드를 `draw()` 함수에 추가하세요.

```js
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI \* 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}
```

여러분의 코드를 저장하고, 다시 실행해보세요. 이번에는 흔적없이 공이 움직이는 것을 보실 수 있을 것입니다. 매 10밀리초마다 캔버스는 지워지고, 새로운 x와 y값의 좌표를 가지는 공이 다음 프레임에 그려지게 되는 것이죠.

코드 정리하기
-------

다음 강좌에서도 계속해서 몇가지 명령들을 `draw()` 함수에다 추가해야 합니다. 그렇기 때문에 코드를 최대한 간단하고 깨끗하게 유지하는 것이 좋습니다. 공을 움직이는 코드를 분리된 함수로 옮기는 것 부터 시작해보죠!

현재의 draw() 함수를 다음의 분리된 두 함수로 바꿔주세요.

```js
function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI \* 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  x += dx;
  y += dy;
}
```

여러분의 코드와 비교해보세요
---------------

아래의 라이브 데모에서 이 강의의 완성된 코드를 확인할 수 있습니다. 어떻게 작동하는지 더 잘 이해하기 위해 플레이 해보세요.

연습해보기: 움직이는 공의 속도를 바꾸거나, 움직이는 방향을 바꿔보세요.

다음 단계로
------

우리는 공을 그리고 움직이게 만들었지만, 캔버스 모서리 밖으로 사라져버립니다. 세 번째 챕터에서는 공이 벽으로부터 튕겨 나오기 위한 방법을 알아볼 것입니다.

* « 이전
* 다음 »


점수 추가와 승패 판정 방법 - 게임 개발

점수 추가와 승패 판정 방법
===============

* « 이전
* 다음 »

이번 단계는 Gamedev Canvas tutorial의 8번째 단계입니다. Gamedev-Canvas-workshop/lesson8.html에서 이번 단계의 소스 코드를 확인할 수 있습니다.

벽돌 깨기 기능은 잘 작동합니다. 하지만 더 나은 게임이 되기 위해서, 유저가 벽돌을 깰 때마다 점수를 얻고, 그 점수를 기록하는 점수 기능을 만들 수 있습니다.

점수 계산하기
-------

게임 플레이 도중 점수를 볼 수 있다면, 친구들에게 자랑할 수 있을 것입니다. 그러기 위해서는 점수를 기록할 변수가 필요합니다. 작성중인 JS파일의 변수 영역의 하단에, 아래 코드를 추가합시다.

```js
var score = 0;
```

점수 화면을 만들고, 업데이트를 하기 위해서 `drawScore()` 함수가 필요합니다. 아래 코드를 `collisionDetection()` 함수 아래에 추가합시다.

```js
function drawScore() {
  ctx.font = "16px Arial";
  ctx.fillStyle = "#0095DD";
  ctx.fillText("Score: " + score, 8, 20);
}
```

텍스트를 캔버스 안에 그리는 것은 도형을 그리는 작업과 비슷합니다. 폰트를 정의하는 것은 CSS에서의 작업과 같습니다. — `font()` (en-US) 함수에서 크기와 타입을 설정할 수 있습니다. 그런 다음 `fillStyle()` (en-US) 함수를 사용하여 글꼴의 색상을 설정하고 `fillText()` (en-US) 함수를 이용해서 캔버스에 배치될 실제 텍스트와 배치 위치를 설정하는 데 사용합니다. 첫 번째 매개 변수는 텍스트 자체입니다. 위의 코드는 현재 점수를 나타내며 마지막 두 매개 변수는 텍스트가 캔버스에 배치될 좌표입니다.

벽돌이 깨질 때마다 점수 변수의 값을 증가시키기 위해서 `collisionDetection()` 함수에 강조 표시된 코드를 입력하여 수정합시다.

```js
function collisionDetection() {
  for (var c = 0; c < brickColumnCount; c++) {
    for (var r = 0; r < brickRowCount; r++) {
      var b = bricks[c][r];
      if (b.status == 1) {
        if (
          x > b.x &&
          x < b.x + brickWidth &&
          y > b.y &&
          y < b.y + brickHeight
        ) {
          dy = -dy;
          b.status = 0;
          score++;
        }
      }
    }
  }
}
```

`draw()` 함수 안에서 위 함수를 호출하면 호출 될 때마다 다시 그리기 때문에 점수 변동을 확인할 수 있습니다. `draw()` 아래 코드를 `drawPaddle()` 아래에서 호출합니다.

```js
drawScore();
```

모든 벽돌이 파괴되었을 때 승리 메시지 표시
------------------------

점수가 오르는 것은 좋지만, 평생 점수가 올라가진 않을 것입니다. 모든 벽돌의 파괴가 결국 게임의 주된 목적이기 때문에 모든 점수를 얻는다면 승리 메시지를 표시해야 합니다. `collisionDetection()`함수에 강조된 코드를 붙여넣읍시다.

```js
function collisionDetection() {
  for (var c = 0; c < brickColumnCount; c++) {
    for (var r = 0; r < brickRowCount; r++) {
      var b = bricks[c][r];
      if (b.status == 1) {
        if (
          x > b.x &&
          x < b.x + brickWidth &&
          y > b.y &&
          y < b.y + brickHeight
        ) {
          dy = -dy;
          b.status = 0;
          score++;
          if (score == brickRowCount \* brickColumnCount) {
            alert("YOU WIN, CONGRATULATIONS!");
            document.location.reload();
          }
        }
      }
    }
  }
}
```

결국 사용자는 모든 벽돌을 파괴한 순간, 실제로 게임에서 승리할 수 있습니다. 이는 게임과 관련하여 굉장히 중요합니다. `document.location.reload()`기능은 페이지를 다시 로드하고 경고 버튼이 클릭되면 게임을 다시 시작합니다.

코드 비교
-----

최종 코드는 아래와 같습니다. 지금까지 작성한 코드와 비교해 봅시다.

**참고:** **추가 학습**: 벽돌을 깰 때마다 얻는 점수를 늘리고, 게임 클리어 시 최종 점수를 경고창에 표시해 봅시다.

다음 단계
-----

게임은 현재 꽤 멋지게 보입니다. 다음 단계에서는, Mouse controls (마우스로 패들 조종하는 방법)을 통해서 게임을 즐길 수 있습니다.

* « 이전
* 다음 »