aboutsummaryrefslogtreecommitdiff
path: root/files/ru/webassembly/using_the_javascript_api/index.html
blob: d480825a10bb8f6be3386871cb922b24b2a5da4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
---
title: Использование WebAssembly JavaScript API
slug: WebAssembly/Using_the_JavaScript_API
tags:
  - API
  - JavaScript
  - WebAssembly
translation_of: WebAssembly/Using_the_JavaScript_API
---
<div>{{WebAssemblySidebar}}</div>

<p class="summary">Если вы уже <a href="/ru/docs/WebAssembly/C_to_wasm">компилировали модуль из другого языка, используя такие инструменты как Emscripten</a>, или загружали и запускали код, то следующим шагом будет углубленное изучение возможностей WebAssembly JavaScript API. Эта статья даст необходимые знания по этому вопросу.</p>

<div class="note">
<p><strong>Примечание</strong>: Если вы незнакомы с фундаментальными понятиями, упомянутыми в этой статье, и вам нужны дополнительные объяснения, то вам нужно сначала прочитать про <a href="/ru/docs/WebAssembly/Concepts">Основы WebAssembly</a>.</p>
</div>

<h2 id="Несколько_простых_примеров">Несколько простых примеров</h2>

<p>Давайте запустим несколько примеров, которые объяснят как использовать WebAssembly JavaScript API, и как использовать его для загрузки wasm-модуля в web-странице.</p>

<div class="note">
<p><strong>Примечание</strong>: Вы можете найти примеры кода в нашем репозитории <a href="https://github.com/mdn/webassembly-examples">webassembly-examples</a> на GitHub.</p>
</div>

<h3 id="Подготовка_примера">Подготовка примера</h3>

<ol>
 <li>Для начала нам нужен wasm-модуль! Возьмите наш файл <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/simple.wasm">simple.wasm</a> и сохраните копию в новой директории на своем локальном компьютере.</li>
 <li>Далее, давайте создадим в той же директории что и wasm-модуль простой HTML-файл и назовем его <code>index.html</code> (можно использовать <a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">HTML шаблон</a> если вы этого еще не сделали).</li>
 <li>Теперь, для того чтобы понять что происходит в коде модуля, давайте взглянем на его текстовое представление (которое мы также встречали в <a href="/en-US/docs/WebAssembly/Text_format_to_wasm#A_first_look_at_the_text_format">Перевод из текстового формата WebAssembly в wasm</a>):
  <pre>(module
  (func $i (import "imports" "imported_func") (param i32))
  (func (export "exported_func")
    i32.const 42
    call $i))</pre>
 </li>
 <li>Во второй строчке вы видите что import имеет двухуровневое пространство имен - внутренняя функция <code>$i</code> импортирована из <code>imports.imported_func</code>. Нам нужно создать это двухуровневое пространство имен в JavaScript-объекте, который будет импортирован в wasm-модуль. Создайте <code>&lt;script&gt;&lt;/script&gt;</code> элемент в своем HTML-файле, и добавьте следующий код:
  <pre class="brush: js">var importObject = {
  imports: { imported_func: arg =&gt; console.log(arg) }
};</pre>
 </li>
</ol>

<h3 id="Загрузка_wasm-модуля_в_потоке">Загрузка wasm-модуля в потоке</h3>

<p>Новшество в Firefox 58 - это возможность компилировать и создавать экземпляры (объекты) модулей WebAssembly непосредственно из исходников. Это достигается использованием методов {{jsxref("WebAssembly.compileStreaming()")}} и {{jsxref("WebAssembly.instantiateStreaming()")}}. Эти методы занимают меньше места чем их непотоковые аналоги, потому что они могут преобразовывать байт-код прямо в модуль или экземпляр модуля, исключая необходимость отдельного размещения ответа ({{domxref("Response")}}) в объекте {{domxref("ArrayBuffer")}} после загрузки файла.</p>

<p>Следующий пример (см. наш демонстрационный файл <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/instantiate-streaming.html">instantiate-streaming.html</a> на GitHub и его работу <a href="https://mdn.github.io/webassembly-examples/js-api-examples/instantiate-streaming.html">вживую</a>) показывает как использовать <code>instantiateStreaming()</code> чтобы загрузить wasm-модуль, импортировать JavaScript функцию в него, компилировать, создать его экземпляр и получить доступ к его экспортируемой функции. Все это в одном шаге.</p>

<p>Добавьте этот скрипт ниже первого блока кода:</p>

<pre class="brush: js">WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject)
.then(obj =&gt; obj.instance.exports.exported_func());</pre>

<p>В конце этого действия мы вызываем нашу экспортированную из WebAssembly-функцию <code>exported_func</code>, которая в свою очередь вызывает нашу импортированную JavaScript-функцию <code>imported_func</code>, которая выводит в консоль значение (42), что хранится внутри экземпляра модуля WebAssembly. Если вы сейчас сохраните пример кода и загрузите его в браузер, который поддерживает WebAssembly, вы увидите это в действии!</p>

<div class="note">
<p><strong>Примечание</strong>: Этот замысловатый и запутанный пример почти ничего не делает, но он служит иллюстрацией того, что можно одновременно использовать WebAssembly-код и JavaScript-код в ваших приложениях. Как мы утверждали ранее, технология WebAssembly не призвана заменить JavaScript. Вместо этого две технологии могут работать вместе, усиливая преимущества каждой стороны.</p>
</div>

<h3 id="Загрузка_wasm-модуля_без_потока">Загрузка wasm-модуля без потока</h3>

<p>Если вы не можете или не хотите использовать методы описанные выше, то вы можете использовать вместо этого непотоковые методы {{jsxref("WebAssembly.compile")}} / {{jsxref("WebAssembly.instantiate")}}.</p>

<p>Эти методы не получают непосредственно доступ к байт-коду, так что требуется дополнительный шаг помещения ответа загрузки файла в объект {{domxref("ArrayBuffer")}} перед компилированием и созданием экземпляра wasm-модуля.</p>

<p>Эквивалентный код будет выглядить так:</p>

<pre class="brush: js">fetch('simple.wasm').then(response =&gt;
  response.arrayBuffer()
).then(bytes =&gt;
  WebAssembly.instantiate(bytes, importObject)
).then(results =&gt; {
  results.instance.exports.exported_func();
});</pre>

<h3 id="Просмотр_wasm_в_инструментах_разработчика">Просмотр wasm в инструментах разработчика</h3>

<p>В Firefox 54+, в отладочной панели инструментов разработчика имеется возможность отображения текстового представления любого wasm-кода, включенного в веб-страницу. Для того чтобы просмотреть его, вы можете перейти на отладочную панель и нажать на пункт "wasm://".</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/15823/wasm-debug.png" style="display: block; height: 317px; margin: 0px auto; width: 1019px;"></p>

<p>В ближайших версиях в Firefox, в дополнении к просмотру wasm-кода как текста, разработчики будут иметь возможность отлаживать wasm используя текстовый формат (устанавливать точки останова, изучать стек вызовов, построчно переходить, и.т.д). См.<span class="watch-title" dir="ltr" id="eow-title" title="WebAssembly debugging with Firefox DevTools"><a href="https://www.youtube.com/watch?v=R1WtBkMeGds"> WebAssembly debugging with Firefox DevTools</a></span> в видео-анонсе.</p>

<h2 id="Память">Память</h2>

<p>В низкоуровневой модели памяти WebAssembly, память представлена как диапазон смежных байт, называемых линейной памятью (<a href="http://webassembly.org/docs/semantics/#linear-memory">Linear Memory</a>), которая внутри модуля читается и записывается <a href="http://webassembly.org/docs/semantics/#linear-memory-accesses">инструкциями загрузки и размещения</a> значений. В этой модели памяти, любая инструкция загрузки или размещения может получить доступ к любому байту всей линейной памяти. Это необходимо для полноценного представления таких концепций языков C/C++ как указатели.</p>

<p>В отличии от C/C++ программы, где доступный диапазон памяти ограничен процессом, память доступная отдельному экземпляру WebAssembly ограничена до одного специфического (потенциально очень маленького) диапазона, который содержится в объекте памяти WebAssembly. Это позволяет единственному web-приложению использовать множество независимых библиотек (использующих WebAssembly) которые могут иметь отдельные и полностью изолированные друг от друга диапазоны памяти.</p>

<p>В JavaScript-коде, объект памяти WebAssembly можно считать объектом ArrayBuffer c изменяемыми размерами. Одно веб-приложение может создавать много таких независимых объектов памяти. Вы можете создать новый объект, используя конструктор WebAssembly.Memory(), который принимает аргументы начального и максимального размера буфера (опционально).</p>

<p>Давайте исследуем эту возможность рассмотрев небольшой пример.</p>

<p>Создайте еще одну простую HTML страницу (скопируйте <a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">HTML шаблон</a>) и назовите её <code>memory.html</code>. Добавьте <code>&lt;script&gt;&lt;/script&gt;</code> элемент на страницу.</p>

<ol>
 <li>
  <p>Добавьте следующую строку в начало нашего скрипта, для создания экземпляра объекта памяти:</p>

  <pre class="brush: js">var memory = new WebAssembly.Memory({initial:10, maximum:100});</pre>

  <p>Единицы измерения начальной (<code>initial</code>) и максимальной (<code>maximum</code>) памяти имеют фиксированый размер в 64KB. Это означает, что в нашем случае объект памяти при создании имеет 640KB, а его максимальный возможный размер будет 6.4MB.</p>

  <p>Объект памяти WebAssembly предоставляет свой хранимый диапазон байт через getter/setter свойства buffer, которое возвращает объект ArrayBuffer. Для примера, чтобы записать число 42 в первое слово линейной памяти, вы можете сделать это:</p>

  <pre class="brush: js">new Uint32Array(memory.buffer)[0] = 42;</pre>

  <p>вы можете возвратить значение используя этот код:</p>

  <pre class="brush: js">new Uint32Array(memory.buffer)[0]</pre>
 </li>
 <li>
  <p>Попробуйте сделать это в вашем примере - сохраните то, что вы сделали, загрузите его в браузере, после чего попробуйте ввести вышеупомянутые строчки в JavaScript-консоль.</p>
 </li>
</ol>

<h3 id="Расширение_памяти">Расширение памяти</h3>

<p>Объект памяти может быть расширен с помощью вызова метода {{jsxref("Memory.prototype.grow()")}}, где аргументом будет количество единиц (размером в 64KB) памяти WebAssembly:</p>

<pre class="brush: js">memory.grow(1);</pre>

<p>При превышении максимального значения, указанного при создании объекта памяти, будет выброшено исключение {{jsxref("WebAssembly.RangeError")}}. Движок использует предоставленные верхние границы для резервирования памяти заранее, что делает расширение памяти более эффективным.</p>

<div class="blockIndicator note">
<p><strong>Примечание</strong>: Так как размер объекта {{domxref("ArrayBuffer")}} неизменен, после успешного вызова метода {{jsxref("Memory.prototype.grow()")}} свойство buffer объекта памяти будет возвращать уже новый объект {{domxref("ArrayBuffer")}} (с новым размером в свойстве byteLength) и любые предыдущие объекты ArrayBuffer станут в некотором роде “отсоединенными”, или отключенными от низкоуровневой памяти, к которой они ранее относились.</p>
</div>

<p>Подобно функциям, диапазоны линейной памяти могут быть импортированы или определены внутри модуля. Также, модуль имеет возможность экспортировать свою память. Это означает, что JavaScript-код может получить доступ к объекту памяти WebAssembly либо c помощью создания нового объекта через конструктор <code>WebAssembly.Memory</code> и передачи его в импортируемый объект, либо с помощью получения объекта памяти через экспортируемый объект (через <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance/exports">Instance.prototype.exports</a></code>).</p>

<h3 id="Более_сложный_пример">Более сложный пример</h3>

<p>Давайте сделаем вышеупомянутые утверждения понятнее, рассмотрев более сложный пример работы с памятью, где WebAssembly-модуль импортирует объект памяти, который мы определили ранее, после чего JavaScript-код наполняет его с помощью массива целых чисел, а экспортируемая wasm-функция суммирует их.</p>

<ol>
 <li>
  <p>Сопируйте файл <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/memory.wasm">memory.wasm</a> в локальную директорию в которой вы работаете.</p>

  <div class="note">
  <p><strong>Примечание</strong>: Вы можете увидеть текстовое представление модуля в файле <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/memory.wat">memory.wat</a>.</p>
  </div>
 </li>
 <li>
  <p>Откройте ваш файл <code>memory.html</code> и добавьте следующий код снизу вашего основного скрипта для загрузки, компилирования и создания экземпляра wasm-модуля:</p>

  <pre class="brush: js">WebAssembly.instantiateStreaming(fetch('memory.wasm'), { js: { mem: memory } })
.then(results =&gt; {
  // add code here
});</pre>
 </li>
 <li>
  <p>Так как модуль экспортирует свою память, которая была передана экземпляру этого модуля при его создании, мы можем наполнить ранее импортированный массив прямо в линейной памяти экземпляра модуля (<code>mem</code>), и вызвать экспортированную функцию <code>accumulate()</code> для расчета суммы значений. Добавьте следующий код, в обозначенном месте: </p>

  <pre class="brush: js">var i32 = new Uint32Array(memory.buffer);

for (var i = 0; i &lt; 10; i++) {
  i32[i] = i;
}

var sum = results.instance.exports.accumulate(0, 10);
console.log(sum);</pre>
 </li>
</ol>

<p>Обратите внимание на то, что мы создаем представление данных {{domxref("Uint32Array")}} с помощью свойства buffer объекта памяти (<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/buffer">Memory.prototype.buffer</a></code>), а не самого объекта памяти.</p>

<p>Импорт памяти почти такой же как импорт функций, только вместо JavaScript функций передаются объекты памяти. Импорт памяти полезен по двум причинам:</p>

<ul>
 <li>Он позволяет JavaScript-коду получать и создать начальное содержание памяти перед или одновременно с компиляцией модуля.</li>
 <li>Он позволяет импортировать один объект памяти во множество экземпляров модулей, что является ключевым элементом для реализации динамического связывания в WebAssembly.</li>
</ul>

<div class="note">
<p><strong>Примечание</strong>: Вы можете найти полную демонстрацию в файле <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/memory.html">memory.html</a> (<a href="https://mdn.github.io/webassembly-examples/js-api-examples/memory.html">см. ее также вживую</a>) — эта версия использует функцию <code><a href="https://github.com/mdn/webassembly-examples/blob/master/wasm-utils.js">fetchAndInstantiate()</a></code>.</p>
</div>

<h2 id="Таблицы">Таблицы</h2>

<p>Таблица WebAssembly - это расширяемый типизированный массив <a href="https://en.wikipedia.org/wiki/Reference_(computer_science)">ссылок</a>, доступ к которому может быть получен из JavaScript и WebAssembly кода. Так как линейная память предоставляет расширяемый массив незащищенных байт, слишком небезопасно размещать там ссылки, так как для движка ссылка является доверенным значением, чьи байты не должны быть прочитаны или записаны кодом напрямую по причинам безопасности, переносимости и стабильности.</p>

<p>У таблиц есть тип элемента, который ограничивает тип возможной ссылки, который может быть размещен в таблице. В текущей версии WebAssembly, только один тип ссылки используется в WebAssembly коде - функции - и поэтому существует только один возможный тип элемента. В следующих версиях их количество будет увеличено.</p>

<p>Ссылки на функции необходимы для компиляции в таких языках как C/C++, которые имеют указатели на функции. В родной реализации C/C++, указатель на функцию представлен прямым адресом на код функции в виртуальном адресном пространстве процесса, и потому для ранее упомянутой безопасности, они не могут быть размещены прямо в линейной памяти. Вместо этого ссылки на функции размещаются в таблице, а её индексы, которые являются целыми числами могут быть размещены в линейной памяти и переданы куда угодно.</p>

<p><span class="tlid-translation translation"><span title="">Когда приходит время для вызова указателя на функцию, вызывающая сторона WebAssembly предоставляет индекс, который затем может быть проверен на безопасность по таблице перед индексацией и вызовом ссылки на индексированную функцию. Таким образом, таблицы в настоящее время являются лучшим низкоуровневым примитивом, используемым для безопасной и удобной компиляции низкоуровневых возможностей языка программирования.</span></span></p>

<p>Таблицы могут изменятся с помощью метода <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/set">Table.prototype.set()</a></code>, который обновляет одно из значений в таблице, и метода <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/grow">Table.prototype.grow()</a></code>, который увеличивает количество значений, которое может быть размещено в таблице. Это позволяет этому "непрямо-вызываемому набору функций" изменяться со временем, что необходимо для <a href="http://webassembly.org/docs/dynamic-linking/">техник динамического связывания</a>. Изменения немедленно становятся доступными с помощью метода <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get">Table.prototype.get()</a></code> в JavaScript коде и wasm-модулях.</p>

<h3 id="Пример_таблицы">Пример таблицы</h3>

<p>Давайте взглянем на простой пример таблицы - модуль WebAssembly, который создает и экспортирует таблицу с двумя элементами: элемент под индексом 0 возвращает 13, а элемент под индексом 1 возвращает 42.</p>

<ol>
 <li>
  <p>Сделайте локальную копию файла <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/table.wasm">table.wasm</a> в новой директории.</p>

  <div class="note">
  <p><strong>Примечание</strong>: Вы можете посмотреть текстовое представление модуля в файле <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/table.wat">table.wat</a>.</p>
  </div>
 </li>
 <li>
  <p>Создайте новую копию нашего <a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">HTML шаблона</a> в той же директории и назовите его table.html.</p>
 </li>
 <li>
  <p>Как и раньше загрузите, компилируйте, и создайте экземпляр вашего wasm-модуля, добавив следующий код в {{htmlelement("script")}} элемент в тело документа:</p>

  <pre class="brush: js">WebAssembly.instantiateStreaming(fetch('table.wasm'))
.then(function(results) {
  // add code here
});</pre>
 </li>
 <li>
  <p>Теперь давайте получим доступ к данным в таблицах - добавим следующие строки в ваш код, в обозначенном месте:</p>

  <pre class="brush: js">var tbl = results.instance.exports.tbl;
console.log(tbl.get(0)());  // 13
console.log(tbl.get(1)());  // 42</pre>
 </li>
</ol>

<p>Этот код получает доступ к каждой ссылке на функцию, которая размещена в таблице, после чего вызывает её и выводит хранимое значение в консоль. Обратите внимание, что каждая ссылка на функцию получена с помощью вызова метода <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get">Table.prototype.get()</a></code>, после чего мы добавили пару круглых скобок для вызова самой функции.</p>

<div class="note">
<p><strong>Примечание</strong>: Вы можете найти нашу полную демонстрацию в файле <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/table.html">table.html</a> (см. ее также <a href="https://mdn.github.io/webassembly-examples/js-api-examples/table.html">вживую</a>) — эта версия использует функцию <code><a href="https://github.com/mdn/webassembly-examples/blob/master/wasm-utils.js">fetchAndInstantiate()</a></code>.</p>
</div>

<h2 id="Глобальные_переменные">Глобальные переменные</h2>

<p>WebAssembly имеет возможность создавать экземпляры глобальных переменных, доступных как в JavaScript так и в экземплярах модулей WebAssembly ({{jsxref("WebAssembly.Module")}}) посредством импорта или экспорта. Это очень полезная возможность, которая позволяет динамически связывать несколько модулей. Для создания глобальной переменной WebAssembly внутри вашего JavaScript-кода, используйте конструктор {{jsxref("WebAssembly.Global()")}}, который выглядит так:</p>

<pre class="brush: js">const global = new WebAssembly.Global({value:'i32', mutable:true}, 0);</pre>

<p>Вы можете видеть, что он принимает 2 параметра:</p>

<ul>
 <li>Обьект, который содержит 2 свойства, описывающих глобальную переменную:
  <ul>
   <li><code>value</code>: это тип данных, который может быть одним из типов данных, позволенных внутри WebAssembly модуля — <code>i32</code>, <code>i64</code>, <code>f32</code>, или <code>f64</code>.</li>
   <li><code>mutable</code>: булево значение, определяющее что переменная может изменяться.</li>
  </ul>
 </li>
 <li>Значение, которое содержит текущее значение переменной. Это может быть любое значение для типа к которому оно относится.</li>
</ul>

<p>Что мы будем с этим делать? В следующем примере мы определим глобальную, изменяемую переменную с типом i32 и значением 0.</p>

<p>Значение глобальной переменной будет изменено на число <code>42</code> используя свойство <code>Global.value</code>, а после на <code>43</code> используя экспортированную функцию <code>incGlobal()</code> из модуля <code>global.wasm</code> (это добавит 1 к установленному значению и возвратит новое).</p>

<pre class="brush: js">const output = document.getElementById('output');

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

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}) =&gt; {
    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);
});</pre>

<div class="note">
<p><strong>Примечание</strong>: Вы можете увидеть этот пример вживую на <a href="https://mdn.github.io/webassembly-examples/js-api-examples/global.html"> GitHub</a>; смотрите также <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/global.html">исходники</a>.</p>
</div>

<h2 id="Множественность">Множественность</h2>

<p>К этому моменту мы продемонстрировали использование всех ключевых составных элементов WebAssembly, и сейчас самое время рассказать о концепции множественности. Она позволяет WebAssembly иметь множество преимуществ с точки зрения архитектурной эффективности:</p>

<ul>
 <li>Один модуль может иметь N экземпляров, точно так же как одно определение функции может произвести N замыканий.</li>
 <li>Один экземпляр модуля может использовать от 0 до 1 объекта памяти, который предоставляет “адресное пространство” экземпляра модуля. Будущие версии WebAssembly позволят иметь 0–N экземпляров объектов на один экземпляр модуля (см. <a href="http://webassembly.org/docs/future-features/#multiple-tables-and-memories">Несколько таблиц и объектов памяти</a>).</li>
 <li>Один экземпляр модуля может использовать от 0 до 1 объекта таблицы - это “адресное пространство для функций” экземпляра модуля используется для реализации С/С++ указателей на функции. Будущие версии WebAssembly позволят иметь 0–N экземпляров таблиц на один экземпляр модуля.</li>
 <li>Один объект памяти или объект таблицы может быть использован в 0-N экземплярах модулей - эти все экземпляры будут разделять одно и то же адресное пространство, позволяя выполнять <a href="http://webassembly.org/docs/dynamic-linking">динамическое связывание</a>.</li>
</ul>

<p>Чтобы ознакомится с множественностью в действии, смотрите нашу объясняющую статью <a href="/en-US/docs/WebAssembly/Understanding_the_text_format#Mutating_tables_and_dynamic_linking">Изменяющиеся таблицы и динамическое связывание</a>.</p>

<h2 id="Резюме">Резюме</h2>

<p>В этой статье-путеводителе по основам WebAssembly JavaScript API вы включали модули WebAssembly в среду JavaScript, использовали их функции, объекты памяти, таблицы и глобальные переменные. <span class="tlid-translation translation"><span title="">Мы также затронули концепцию множественности</span></span>.</p>

<h2 id="Смотрите_также">Смотрите также</h2>

<ul>
 <li><a href="http://webassembly.org/">webassembly.org</a></li>
 <li><a href="/ru/docs/WebAssembly/Concepts">Основы WebAssembly</a></li>
 <li><a href="https://research.mozilla.org/webassembly/">WebAssembly на Mozilla Research</a></li>
</ul>