Автор: Дэнни Го
Перевод: сумасшедший технический ботаник
оригинал:blog.log robot.com/he-intro читать…
Копирование без разрешения строго запрещено
WebAssembly(Wasm) — это относительно новая функция веб-браузеров, но она расширяет функциональные возможности Интернета как платформы приложений-служб.
Обучение использованию WebAssembly может быть трудным делом для веб-разработчиков, ноAssemblyScriptПредусмотрен обходной путь. Давайте сначала посмотрим, почему WebAssembly является многообещающей технологией, а затем посмотрим, как AssemblyScript может раскрыть ее потенциал.
WebAssembly
WebAssembly — это низкоуровневый языковой браузер, предоставляющий разработчикам веб-компилятор, отличный от JavaScript. Это позволяет коду веб-сайта выполняться с почти естественной скоростью в безопасной среде песочницы.
Он был разработан с использованием входных данных, представленных всеми основными браузерами (Chrome, Firefox, Safari и Edge), ониБыл достигнут консенсус по дизайну, эти браузеры теперь поддерживают WebAssembly.
WebAssembly поставляется в двоичном формате, а это означает, что WebAssembly имеет преимущества по размеру и времени загрузки по сравнению с JavaScript. Но он также имеет простой для пониманиятекстовое представление.
Когда WebAssembly впервые появился, некоторые разработчики думали, что он может в конечном итоге заменить JavaScript в качестве основного языка Интернета. Но лучше всего рассматривать WebAssembly как хорошо интегрированную платформу для новых и существующих веб-инструментов.Расширенные цели.
Вместо того, чтобы заменить существующие варианты использования JavaScript, WebAssembly привлекает больше людей, поскольку представляет новые варианты использования. В настоящее время WebAssembly не имеет прямого доступа к DOM, большинство веб-сайтов хотят использовать JavaScript, и после многих лет оптимизации JavaScript работает довольно быстро. Следующая веб-сборкаСписок возможных вариантов использованияПример:
- игра
- Научная визуализация и моделирование
- САПР-приложение
- Редактирование изображений/видео
Что общего у этих приложений, так это то, что они часто рассматриваются как настольные приложения. Обеспечивая почти исходную производительность для задач, интенсивно использующих ЦП, WebAssembly делает возможным перенос этих программ в Интернет.
Существующие веб-сайты также могут извлечь выгоду из WebAssembly. Фигма(www.figma.com/) представляет собой реальный пример, который значительно сокращает время загрузки за счет использования WebAssembly. Если на веб-сайте используется код, требующий больших вычислительных ресурсов, его можно заменить на WebAssembly для повышения производительности.
Возможно, теперь вам интересно, как использовать WebAssembly. можно выучить сам язык инаписать напрямую, а на самом деле так и задуманоЦели компиляции для других языков. этодизайнДля хорошей поддержки C и C++ язык GoДобавлена экспериментальная поддержка в версии 1.11.Ржавчина такжемного инвестиций.
Но, возможно, вы не хотите изучать или использовать один из этих языков, чтобы использовать WebAssembly. Вот для чего существует AssemblyScript.
AssemblyScript
AssemblyScript — это компилятор, который преобразует TypeScript в WebAssembly. TypeScript, разработанный Microsoft, добавляет типы в JavaScript. оно сталодовольно популярный, даже для тех, кто не знаком с ним, AssemblyScript предоставляет только ограниченный набор функций TypeScript, поэтому для начала не требуется много времени. .
Поскольку он очень похож на JavaScript, то AssemblyScript позволяет веб-разработчикам легко интегрировать WebAssembly в свои веб-сайты без необходимости использовать совершенно другой язык.
проверять
Давайте напишем наш первый модуль AssemblyScript (весь приведенный ниже код можно найти вна GitHubоказаться). мы должныNode.jsМинимальная версия – 8, чтобы получить [поддержку WebAssembly](developer.Mozilla.org/this-cn/docs/…/Global_Objects/WebAssembly#Browser_compatibility).
Перейдите в пустой каталог, создайтеpackage.json
файл, а затем установите AssemblyScript. Обратите внимание, что нам нужно перейти прямо изего репозиторий GitHubУстановить. Он еще не выпущен на npm, потому что разработчики AssemblyScriptНе рассмотрел, готов ли компиляторМожет поддерживать широкое использование.
mkdir assemblyscript-demo
cd assemblyscript-demo
npm init
npm install --save-dev github:AssemblyScript/assemblyscript
использоватьasinit
Команда генерирует файл скаффолдинга:
npx asinit .
нашpackage.json
Теперь должен быть включен следующий скрипт:
{
"scripts": {
"asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug",
"asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize",
"asbuild": "npm run asbuild:untouched && npm run asbuild:optimized"
}
}
высший уровеньindex.js
Это выглядит так:
const fs = require("fs");
const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm"));
const imports = {
env: {
abort(_msg, _file, line, column) {
console.error("abort called at index.ts:" + line + ":" + column);
}
}
};
Object.defineProperty(module, "exports", {
get: () => new WebAssembly.Instance(compiled, imports).exports
});
Это позволяет нам использовать как обычный модуль JavaScript так же легкоrequire
Модули веб-сборки.
assembly
Каталог содержит наш исходный код AssemblyScript. Сгенерированный пример представляет собой простую функцию сложения.
export function add(a: i32, b: i32): i32 {
return a + b;
}
Сигнатура функции такая же, как в TypeScript, она используетi32
Причина в том, что AssemblyScript использует WebAssembly.конкретные целочисленные типы и типы с плавающей запятой, а не TypeScriptОбщийnumber
Типы.
Давайте построим пример.
npm run asbuild
Каталог сборки теперь должен содержать следующие файлы:
optimized.wasm
optimized.wasm.map
optimized.wat
untouched.wasm
untouched.wasm.map
untouched.wat
Мы получили обычную версию и оптимизированную версию сборки. Для каждой сборки есть.wasm
бинарный файл, а.wasm.map
Сопоставление источника, а двоичный файл.wat
Текстовое представление. Текстовое представление предназначено для чтения людьми, но сейчас нам не нужно его читать или понимать — одна из целей использования AssemblyScript заключается в том, что нам не нужно использовать необработанный WebAssembly.
Запустите Node и используйте скомпилированный модуль, как любой другой модуль.
$ node
Welcome to Node.js v12.10.0.
Type ".help" for more information.
> const add = require('./index').add;
undefined
> add(3, 5)
8
Это все, что вам нужно для вызова WebAssembly из Node!
Добавить скрипт просмотра
Для простоты разработки рекомендую использовать каждый раз при изменении исходного кодаonchangeАвтоматически перестраивать модули, потому что AssemblyScriptНе включая режим мониторинга.
npm install --save-dev onchange
существуетpackage.json
Добавитьasbuild:watch
сценарий. Включать-i
flag, чтобы запустить первоначальную сборку сразу после выполнения команды.
{
"scripts": {
"asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug",
"asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize",
"asbuild": "npm run asbuild:untouched && npm run asbuild:optimized",
"asbuild:watch": "onchange -i 'assembly/**/*' -- npm run asbuild"
}
}
Теперь вы можете запуститьasbuild:watch
, без необходимости постоянно перезапускатьasbuild
.
представление
Давайте напишем базовый тест, чтобы точно увидеть, какой прирост производительности вы можете получить. WebAssembly специализируется на решении ресурсоемких задач, таких как числовые вычисления, поэтому мы используем функцию, чтобы определить, является ли целое число простым.
Наша эталонная реализация показана ниже. Это наивное решение методом грубой силы, поскольку наша цель — выполнить много вычислений.
function isPrime(x) {
if (x < 2) {
return false;
}
for (let i = 2; i < x; i++) {
if (x % i === 0) {
return false;
}
}
return true;
}
Эквивалентная версия сборки требует только некоторые аннотации типа:
function isPrime(x: u32): bool {
if (x < 2) {
return false;
}
for (let i: u32 = 2; i < x; i++) {
if (x % i === 0) {
return false;
}
}
return true;
}
мы будем использоватьBenchmark.js.
npm install --save-dev benchmark
Создайтеbenchmark.js
:
const Benchmark = require('benchmark');
const assemblyScriptIsPrime = require('./index').isPrime;
function isPrime(x) {
for (let i = 2; i < x; i++) {
if (x % i === 0) {
return false;
}
}
return true;
}
const suite = new Benchmark.Suite;
const startNumber = 2;
const stopNumber = 10000;
suite.add('AssemblyScript isPrime', function () {
for (let i = startNumber; i < stopNumber; i++) {
assemblyScriptIsPrime(i);
}
}).add('JavaScript isPrime', function () {
for (let i = startNumber; i < stopNumber; i++) {
isPrime(i);
}
}).on('cycle', function (event) {
console.log(String(event.target));
}).on('complete', function () {
const fastest = this.filter('fastest');
const slowest = this.filter('slowest');
const difference = (fastest.map('hz') - slowest.map('hz')) / slowest.map('hz') * 100;
console.log(`${fastest.map('name')} is ~${difference.toFixed(1)}% faster.`);
}).run();
На моей машине запуститеnode benchmark
получил следующие результаты:
AssemblyScript isPrime x 74.00 ops/sec ±0.43% (76 runs sampled)
JavaScript isPrime x 61.56 ops/sec ±0.30% (64 runs sampled)
AssemblyScript isPrime is ~20.2% faster.
Обратите внимание, что этот тест являетсяmicrobenchmarkМы должны внимательно прочитать это.
Для получения дополнительных тестов AssemblyScript я предлагаю вам проверитьТест WasmBoyа такжеЭталонное уравнение волатильности.
загрузочный модуль
Далее используйте наш модуль на сайте.
создать первыйindex.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>AssemblyScript isPrime demo</title>
</head>
<body>
<form id="prime-checker">
<label for="number">Enter a number to check if it is prime:</label>
<input name="number" type="number" />
<button type="submit">Submit</button>
</form>
<p id="result"></p>
<script src="demo.js"></script>
</body>
</html>
воссоздатьdemo.js
. Загрузка модулей WebAssembly имеетРазнообразие способов, но наиболее эффективным способом является использованиеWebAssembly.instantiateStreaming
Функция потока для создания и компиляции. Обратите внимание, что еслиassertionЕсли мы потерпим неудачу, нам нужноПредусмотреть функцию прерывания.
(async () => {
const importObject = {
env: {
abort(_msg, _file, line, column) {
console.error("abort called at index.ts:" + line + ":" + column);
}
}
};
const module = await WebAssembly.instantiateStreaming(
fetch("build/optimized.wasm"),
importObject
);
const isPrime = module.instance.exports.isPrime;
const result = document.querySelector("#result");
document.querySelector("#prime-checker").addEventListener("submit", event => {
event.preventDefault();
result.innerText = "";
const number = event.target.elements.number.value;
result.innerText = `${number} is ${isPrime(number) ? '' : 'not '}prime.`;
});
})();
установить сейчасstatic-server. Из-за использованияWebAssembly.instantiateStreaming
, нам нужно создать сервис, модуль должен использоватьMIME typeизapplication/wasm
.
npm install --save-dev static-server
добавить скрипт вpackage.json
середина.
{
"scripts": {
"serve-demo": "static-server"
}
}
бегатьnpm run serve-demo
и откройте URL-адрес localhost в своем браузере. Отправьте число в форму, и вы получите сообщение о том, является ли число простым или нет. Теперь мы перешли от кодирования на AssemblyScript к его фактическому использованию на веб-сайте.
В заключение
Webassembly и расширение через AssemblyScript не делают каждый веб-сайт невероятно быстрым, но это и не важно. Webassembly интересен тем, что позволяет большему количеству приложений работать в Интернете.
Точно так же AssemblyScript делает WebAssembly доступным для большего числа разработчиков, что позволяет нам по умолчанию использовать JavaScript, но использовать WebAssembly, когда требуется работа с интенсивными вычислениями.