Автор этой статьи: Лю Гуаньюй, старший фронтенд-инженер и технический менеджер 360 Qi Dance Troupe, участвовал во многих крупномасштабных фронтенд-проектах, таких как 360 Navigation, 360 Film and Television, 360 Finance и 360 Games. . Следит за последними достижениями в области стандартов W3C, Интернета вещей и машинного обучения и в настоящее время является членом рабочей группы W3C CSS.
задний план
Энергичная разработка веб-приложений привела к глубоким изменениям в JavaScript, веб-интерфейсе и даже во всем Интернете. Внешний интерфейс стал брать на себя больше обязанностей, поэтому требование эффективности исполнения стало более насущным. В дополнение к эволюции самого языка веб-практики и крупные производители браузеров также постоянно исследуют его. В 2012 году инженеры Mozillia предложили Asm.js и Emscripten, которые позволяли переводить эффективные программы, написанные на C/C++ и различных языках программирования, в JavaScript и запускать их в браузере.
Кроме того, была предложена технология WebAssembly (для краткости wasm), и были быстро созданы различные научно-исследовательские организации, различные цепочки периферийных инструментов постоянно улучшались, а соответствующие экспериментальные данные также убедительно доказывали осуществимость этого пути оптимизации и ускорения.
В частности, в 2018 году рабочая группа W3C WebAssembly выпустила свой первый рабочий проект, содержащийосновной стандарт,JavaScript APIтак же какWeb API. Кроме того, помимо C/C++ и Rust, Golang также официально поддерживает компиляцию wasm. Мы редко видим, чтобы основные основные браузеры единодушно выражали поддержку этой новой технологии, возможно, наступает совершенно новая эра Интернета.
Краткое введение в wasm
открытый васмОфициальный сайт, мы можем видеть его грандиозные технические цели. В дополнение к определению портативного, компактного и быстро загружаемого двоичного формата, есть планы по поддержке мобильных устройств, устройств без браузера и даже устройств IoT, и будет постепенно создаваться ряд цепочек инструментов. Заинтересованные читатели могутздесьСм. официальное объяснение WASM.
Проще говоря, wasm — это не язык программирования, а новый формат байт-кода, в настоящее время все основные браузеры уже поддерживают wasm. В отличие от JavaScript, который необходимо интерпретировать и выполнять, байт-код wasm очень похож на базовый машинный код и может быть загружен и запущен быстро, поэтому производительность значительно выше по сравнению с интерпретацией и выполнением JavaScript.
На следующем рисунке показана текущая (июль 2018 г.) поддержка wasm в основных браузерах.
Помимо работы в браузерах, wasm теперь может работать в средах командной строки, включая NodeJS.
структура инструментальной цепочки wasm
Согласно первоначальной идее, различные языки высокого уровня компилируют собственный исходный код в промежуточное языковое представление (LLVM IR), распознаваемое базовой виртуальной машиной (LLVM) посредством собственных средств компиляции внешнего интерфейса. В настоящее время базовая LLVM может генерировать различные машинные коды из LLVM IR в соответствии с различными архитектурами ЦП и может оптимизировать пространство и производительность при компиляции этих машинных кодов. Большинство языков высокого уровня поддерживают wasm в соответствии с этой структурой. Два шага, упомянутые выше, по очереди также называются интерфейсом компилятора и сервером компилятора.
Код, собранный в WASM, является программой, которая, наконец, делает фактическую работу. Для этого есть текстовый формат под названием S-выражение, с расширением .wast, чтобы проще прочитать программистам. С помощью WABT Toolchain, WASM и WAST могут быть преобразованы друг другу. S-выражение выглядит как:
(module
(type $iii (func (param i32 i32) (result i32)))
(memory $0 0)
(export "memory" (memory $0))
(export "add" (func $assembly/module/add))
(func $assembly/module/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
;;@ assembly/module.ts:2:13
(i32.add
;;@ assembly/module.ts:2:9
(get_local $0)
;;@ assembly/module.ts:2:13
(get_local $1)
)
)
)
Уже существует множество языков высокого уровня, поддерживающих компиляцию wasm, особенноAssemblyScript, основанный на TypeScript и поддерживаемый цепочкой инструментов AssemblyScript, может выполнить окончательное преобразование в wasm.
В соответствии с приведенной выше архитектурой браузеры и различные поставщики операционных сред предоставляют различные операционные поддержки, чтобы сгладить различия, вызванные различными архитектурами ЦП, поэтому им необходимо поддерживать язык высокого уровня wasm и поддерживать только компиляцию в промежуточный код. слой представления языка. Можно предвидеть, что по мере постепенного улучшения комфортности среды разработки к лагерю, поддерживающему wasm, будет присоединяться все больше языков высокого уровня.
Написание wasm на AssemblyScript
В следующей практике нам нужно использоватьAssemblyScriptДля завершения AssemblyScript определяет подмножество TypeScript, которое предназначено для того, чтобы помочь учащимся с опытом работы с TS выполнить компиляцию в wasm с помощью стандартного API JavaScript, тем самым устраняя языковые различия и позволяя программистам с удовольствием писать код.
Проект сборки в основном разделен на три подпроекта:
- AssemblyScript: Основная программа для конвертации TypeScript в wasm
- binaryen.js: Основная программа AssemblyScript преобразуется в базовую реализацию wasm, опираясь наbinaryenБиблиотеки, которые являются оболочками TypeScript для бинарных файлов.
- wast.js: Основная программа AssemblyScript преобразуется в базовую реализацию wasm, опираясь наwastБиблиотека представляет собой инкапсуляцию wast в TypeScript.
Здесь следует отметить, что тулчейн все еще находится в процессе разработки, и отдельные шаги могут быть нестабильны. Мы делаем все возможное, чтобы обеспечить строгость процесса установки и настройки.Если есть какие-либо изменения, пожалуйста, обратитесь кофициальныйОписание имеет преимущественную силу.
Для поддержки компиляции нам сначала нужно установить поддержку AssemblyScript. Чтобы скомпилировать без проблем, вам сначала нужно убедиться, что ваша версия Node выше 8.0. В то же время вам необходимо установить среду выполнения TypeScript.
Давайте начнем:
Шаг 1: Установите зависимости
Чтобы избежать проблемы с более поздними зависимостями, мы сначала устанавливаем поддержку AssemblyScript.
git clone https://github.com/AssemblyScript/assemblyscript.git
cd assemblyscript
npm install
npm link
После выполнения вышеуказанной команды вы можете использовать командуasc
чтобы определить правильность установки. При нормальной установке в командной строке будут отображаться инструкции по использованию команды asc.
Шаг 2: Создайте новый проект
Далее мы создаем новый проект NPM, например: wasmExample. При необходимости вы можете добавить devDependencies ts-node и typescript и установить зависимости. Затем в корневом каталоге проекта мы создаем новый каталог:assembly. Входим в директорию сборки, и заодно добавляем сюда tsconfig.json, содержимое такое:
{
"extends": "../node_modules/assemblyscript/std/assembly.json",
"include": [
"./**/*.ts"
]
}
Шаг 3: Напишите код
Затем мы добавляем простой код ts в этот каталог следующим образом:
export function add(a: i32, b: i32): i32 {
return a + b;
}
Мы сохраняем приведенный выше код TypeScript как: module.ts. Итак, теперь из корневого каталога проекта наша файловая структура выглядит следующим образом:
Шаг 4. Настройте сценарии NPM
Чтобы упростить запуск позже, мы добавим шаг сборки в скрипты npm, открыв package.json в корневом каталоге проекта и изменив поле scripts на:
"scripts": {
"build": "npm run build:untouched && npm run build:optimized",
"build:untouched": "asc assembly/module.ts -t dist/module.untouched.wat -b dist/module.untouched.wasm --validate --sourceMap --measure",
"build:optimized": "asc assembly/module.ts -t dist/module.optimized.wat -b dist/module.optimized.wasm --validate --sourceMap --measure --optimize"
}
Чтобы очистить проект, мы поместили цель компиляции в папку dist корневого каталога проекта.На данный момент нам нужно создать новый каталог dist в корневом каталоге проекта.
Шаг 5: Скомпилируйте
Теперь в корневом каталоге проекта запустим:npm run build
Если ошибки нет, вы увидите, что в каталоге dist сгенерировано 6 файлов.
Нам не нужно сначала вникать в особенности файла. На этом наша работа по компиляции завершена. Внимательные читатели могли заметить, что в приведенной выше команде компиляции используются разные параметры. Эти параметры мы можем набрать прямо в командной строкеasc
для запроса сведений об использовании команд и параметров.
Шаг 6: Представьте результаты компиляции
Теперь у нас есть скомпилированный результат. В настоящее время, поскольку wasm может быть введен только с помощью JavaScript, нам также необходимо добавить скомпилированный wasm в программу на JavaScript.
Мы добавляем код импорта модуля в корневой каталог проекта: module.js следующим образом:
const fs = require("fs");
const wasm = new WebAssembly.Module(
fs.readFileSync(__dirname + "/dist/module.optimized.wasm"), {}
);
module.exports = new WebAssembly.Instance(wasm).exports;
В то же время нам нужен код, использующий модули. Например: index.js, например:
var myModule = require("./module.js");
console.log(myModule.add(1, 2));
Пришел захватывающее время, мы работаем в корневом каталоге проектаnode index.js
, чтобы увидеть, являются ли результаты такими, как мы ожидали. Читатели могут изменить данные вызова в index.js, чтобы проверить правильность модуля. Следует отметить, что поскольку wasm имеет концепцию типов данных, а типы данных являются более точными, чем TypeScript. Поэтому в приведенном выше примере, если ввод не является целым числом (приведенный выше пример относится к i32, определенному wasm), это будет несовместимо с традиционным результатом JavaScript.Например, ваш вызовmyModule.add(2.5, 2)
, результат может быть 4. Поэтому нам нужно обратить пристальное внимание на тип данных при вызове программы wasm.
использовать в браузере
В предыдущих абзацах мы показали, как интегрироваться с NodeJS, На самом деле повышение эффективности более существенно в браузере. Так как же нам использовать наш скомпилированный код в браузере?
JavaScript вызывает wasm
Чтобы JavaScript вызывал wasm, обычно используются следующие шаги:
- Загрузите байт-код wasm.
- После того, как байт-код получен, он конвертируется в массив-буфер, и только эта структура может быть правильно скомпилирована. Приведенный выше ARRAYBUFFER проверяется при компиляции. Убедитесь, что проверка может быть скомпилирована. После компиляции вы передадите Promise Resolve.
- После получения модуля вам необходимо синхронно создать экземпляр модуля через WebAssembly.Instance API.
- Шаги 2 и 3 выше можно заменить эквивалентом создания экземпляра асинхронного API.
- Затем его можно вызвать, как если бы это был модуль JavaScript.
Для полных шагов вы также можете обратиться к блок-схеме ниже:
Вот пример асинхронного кода, который мы назовем async_module.js:
// 异步引入例子
const fs = require("fs");
const readFile = require("util").promisify(fs.readFile);
const getInstance = async (wasm, importObject={}) => {
let buffer = new Uint8Array(wasm)
return await WebAssembly.instantiate(wasm, importObject)
}
let ins;
const noop = () => {};
const exportFun = (obj, funName) => {
return (typeof obj[funName] === "function")
? obj[funName] : noop;
}
async function getModuleFun(filePath, funName ,importObject={}) {
if (ins){
return exportFun(ins, funName)
}
const wasmText = await readFile(filePath);
const mod = await getInstance(wasmText, importObject);
return exportFun(mod.instance.exports, funName)
}
module.exports = getModuleFun;
При вызове мы можем использовать объект wasm для кодирования с помощью следующего кода:
var myModule = require("./async_module.js");
// 调用代码
(async () => {
const fun = await myModule(__dirname + "/dist/module.optimized.wasm", "add")
console.log(fun(1, 2))
console.log(fun(4, 10000))
})()
здесьЭто описание API для работы с wasm во всех JavaScript на данный момент.
Интеграция рабочего процесса загрузки с веб-пакетом
Начиная с webpack4 официально предоставляется схема загрузки wasm по умолчанию. Если ваш веб-пакет является предыдущей версией веб-пакета 4, вам может потребоваться установить что-то вродеassemblyscript-typescript-loader
и другие наборы для разработки.
Версия веб-пакета, используемая в настоящее время автором: 4.16.2, и родная поддержка wasm относительно полная. По официальной информации, позже webpack5 обеспечит более надежную поддержку wasm.
Следующий код может просто импортировать модуль wasm и запуститьnpx webpack
Код может быть скомпилирован автоматически:
import("./module.optimized.wasm").then(module => {
const container = document.createElement("div");
container.innerText = "Hello, WebAssembly.";
container.innerText += " add(1, 2) is " + module.add(1, 2);
document.body.appendChild(container);
});
Управление JavaScript в wasm
Поскольку в настоящее время wasm не может напрямую управлять Домом, если эта операция требуется, могут потребоваться возможности JavaScript.В этом случае нам нужно вызвать JavaScript в wasm.
Обе функции WebAssembly.instance и WebAssembly.instantiate поддерживают второй параметр importObject, функция которого заключается в передаче в wasm модулей JavaScript, которые необходимо вызвать.
В качестве демонстрации давайте изменим приведенный выше код module.js и используем число «*» для представления результата добавления. Здесь мы по-прежнему используем синхронный код для удобства демонстрации, на самом деле чаще используется асинхронный код.
const fs = require("fs");
const wasm = new WebAssembly.Module(
fs.readFileSync(__dirname + "/dist/module.optimized.wasm"), {}
);
module.exports = new WebAssembly.Instance(wasm, {
window:{
show: function (num){
console.log(Array(num).fill("*").join(""))
}
}
}).exports;
абонентindex.js
изменить на:
var myModule = require("./module.js");
myModule.add(1, 2);
В то же время нам нужно изменить исходный код TypeScript:
// 声明从外部导入的模块类型
declare namespace window {
export function show(v: number): void;
}
export function add(a: i32, b: i32): void {
window.show(a + b);
}
Возвращаемся в корневую директорию проекта и перезапускаемnpm run build
.
После этого запуститеnode index.js
Мы видим, что исходный результат представлен числом файлов *. Указывает, что WebAssembly успешно вызвал код JavaScript.
резюме
Для технологии wasm мы резюмируем следующее:
- Стандарт все еще находится в стадии рабочего проекта и не рекомендуется для использования в реальных стабильных проектах.
- Цель высока, и основные производители браузеров и основные основные языки очень заинтересованы в ее продолжении, что подходит для долгосрочного развития в качестве новой технологии.
- В настоящее время в основном поддерживаются последние версии основных браузеров. Если вам нужна совместимость с предыдущими браузерами, особенно с серией IE, хорошего решения нет, а отдельные интерфейсы несовместимы.
- Разработка набора инструментов в настоящее время очень активна, но это также приводит к нестабильности интерфейса, и способ использования может измениться. Различные цепочки инструментов еще не обладают особенно значительными преимуществами в эффективности и зрелости, и все они находятся в зачаточном состоянии.
- Учебных материалов мало, особенно китайских материалов. Это требует определенных затрат энергии, и вам нужно следить за исходным кодом, когда это необходимо.
Несмотря на это, автор по-прежнему очень оптимистично смотрит на перспективы wasm, и возможно хорошее развитие в областях с высокими требованиями к производительности, таких как игры и аудиовизуальные приложения.
использованная литература
- webassembly.org/
- Уууу, эта лошадь plus.com/package/ass…
- GitHub.com/Сборка SCR…
- Я 3.org/TR/2018/WD-…
- Woohoo. IBM.com/developer Я…
- сегмент fault.com/ah/119000000…
- developer.Mozilla.org/en-US/docs/…
- Уууу, эта лошадь plus.com/package/ass…
- blog.CSDN.net/ah986597353/…
- webpack.js.org/
Спасибо
Процесс выбора темы для этой статьи основан на предложениях таких коллег, как Ань Цзя, Ли Сунфэн и Лю Юйчен. После того, как документ был написан, г-н Ли Сунфэн и Лю Юйчэнь дали много соответствующих мнений о пересмотре и настоящим выражают нашу искреннюю благодарность.
Статьи по Теме
- WebAssembly против JavaScript и сценарии его использованияTickets.WeChat.QQ.com/Yes/AI kV ant wq…
- Начало работы с Rust, WebAssembly и WebpackTickets.WeChat.QQ.com/Yes/Смотреть VR04 Agent J4…
- Несколько картинок, чтобы вы поняли WebAssemblyTickets.WeChat.QQ.com/Yes/8K BI HP2RK…
О Еженедельнике Циву
«Qiwu Weekly» — это сообщество передовых технологий, управляемое профессиональной командой «Qiwu Troupe» компании 360. Подписавшись на официальный аккаунт, вы можете отправить нам статью, отправив ссылку прямо на фон.