AssemblyScript 入门指南[每日前端夜话0xEB]

Stella981
• 阅读 811

每日前端夜话****0xEB

每日前端夜话,陪你聊前端。

每天晚上18:00准时推送。

正文共:2459 字

预计阅读时间:10 分钟

作者:Danny Guo

翻译:疯狂的技术宅

来源:logrocket

AssemblyScript 入门指南[每日前端夜话0xEB]

WebAssembly【https://webassembly.org/】(Wasm)是 Web 浏览器中相对较新的功能,但它地扩展了把 Web 作为服务应用平台的功能潜力。

对于 Web 开发人员来说,学习使用 WebAssembly 可能会有一个艰难的过程,但是 AssemblyScript【https://assemblyscript.org/】 提供了一种解决方法。首先让我们看一下为什么 WebAssembly 是一项很有前途的技术,然后再看怎样 AssemblyScript 挖掘潜力。

WebAssembly

WebAssembly 是浏览器的低级语言,为开发人员提供了除 JavaScript 之外的 Web 编译目标。它使网站代码可以在安全的沙盒环境中以接近本机的速度运行。

它是根据所有主流浏览器(Chrome,Firefox,Safari 和 Edge)所代表的意见开发的,他们达成了设计共识【https://lists.w3.org/Archives/Public/public-webassembly/2017Feb/0002.html】,这些浏览器现在都支持 WebAssembly。

WebAssembly 以二进制格式交付,这意味着与 JavaScript 相比,WebAssembly 在大小和加载时间上都具有优势。但是它也有易于理解的文本表示形式【https://developer.mozilla.org/zh-CN/docs/WebAssembly/Understanding\_the\_text\_format】。

当 WebAssembly 首次发布时,一些开发人员认为它有可能最终取代 JavaScript 作为 Web 的主要语言。但是最好把 WebAssembly 看作是与现有 Web 平台良好集成的新工具,这是它的高级目标【https://webassembly.org/docs/high-level-goals/】。

WebAssembly 并没有取代 JavaScript 现有的用例,而是吸引了更多人,因为它引入了新的用例。目前 WebAssembly 还不能直接访问 DOM,大多数网站都希望使用 JavaScript,经过多年的优化,JavaScript 已经相当快了。以下 WebAssembly 可能的使用案例列表【https://webassembly.org/docs/use-cases/】的示例:

  • 游戏

  • 科学的可视化和模拟

  • CAD应用

  • 图像/视频编辑

这些应用共同特点是,它们通常会被看作是桌面应用。通过为 CPU 密集型任务提供接近本机的性能,WebAssembly 使得将这些程序迁移至 Web 成为可行。

现有网站也可以从 WebAssembly 中受益。Figma【https://www.figma.com/】提供了一个真实的例子,它通过使用 WebAssembly 大大缩短了其加载时间。如果网站使用进行大量计算的代码,则可以将其替换为 WebAssembly 以提高性能。

也许现在你对怎样使用 WebAssembly 感兴趣。你可以学习语言本身并直接编写【https://blog.scottlogic.com/2018/04/26/webassembly-by-hand.html】 ,但实际上它打算成为其他语言的编译目标【https://github.com/appcypher/awesome-wasm-langs】 。它被设计【https://webassembly.org/docs/c-and-c++/】为对 C 和 C++ 具有良好的支持,Go语言在 version 1.11 中增加了实验性支持的版本中,Rust 也对其进行了大量投入。

但是也许你并不想为了使用 WebAssembly 而学习或使用其中某种语言。这就是 AssemblyScript 存在的意义。

AssemblyScript

AssemblyScript 是一个把 TypeScript 转换到 WebAssembly 的编译器。由微软开发的 TypeScript 将类型添加到了 JavaScript 中。它已经变得相当受欢迎【https://insights.stackoverflow.com/survey/2019#most-popular-technologies】,即使对于不熟悉它的人,AssemblyScript 只允许 TypeScript 的有限功能子集,因此不需要花太多时间就可以上手。。

因为它与 JavaScript 非常相似,所以 AssemblyScript 使 Web 开发人员可以轻松地将 WebAssembly 整合到他们的网站中,而不必使用完全不同的语言。

试用

让我们编写第一个 AssemblyScript 模块(以下所有代码均可在 GitHub 上【https://github.com/dguo/assemblyscript-demo】找到)。我们需要 Node.js 的最低版本为 8 才能得到 WebAssembly 的支持。

转到一个空目录,创建一个 package.json 文件,然后安装 AssemblyScript。请注意,我们需要直接从它的 GitHub 存储库【https://github.com/AssemblyScript/assemblyscript】安装。它尚未在 npm 上发布,因为 AssemblyScript 开发人员还没有考虑编译器是否已经准备好能够支持广泛使用。

1mkdir assemblyscript-demo2cd assemblyscript-demo3npm init4npm install --save-dev github:AssemblyScript/assemblyscript

使用 asinit 命令生成脚手架文件:

1npx asinit .

我们的 package.json 现在应该包含以下脚本:

1{2  "scripts": {3    "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug",4    "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize",5    "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized"6  }7}

顶层的 index.js 看起来像这样:

 1const fs = require("fs"); 2const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm")); 3const imports = { 4  env: { 5    abort(_msg, _file, line, column) { 6       console.error("abort called at index.ts:" + line + ":" + column); 7    } 8  } 9};10Object.defineProperty(module, "exports", {11  get: () => new WebAssembly.Instance(compiled, imports).exports12});

它使我们能够像使用普通的 JavaScript 模块一样轻松地 require WebAssembly 模块。

assembly 目录中包含我们的 AssemblyScript 源代码。生成的示例是一个简单的加法函数。

1export function add(a: i32, b: i32): i32 {2  return a + b;3}

函数签名就像在 TypeScript 中那样,它之所以使用 i32 的原因是 AssemblyScript 使用了 WebAssembly 的特定整数和浮点类型【https://docs.assemblyscript.org/basics/types】,而不是 TypeScript 的通用 number 类型【。

让我们来构建示例。

1npm run asbuild

build 目录现在应包含以下文件:

1optimized.wasm2optimized.wasm.map3optimized.wat4untouched.wasm5untouched.wasm.map6untouched.wat

我们得到了构建的普通版本和优化版本。对于每个构建版本,都有一个 .wasm 二进制文件,一个 .wasm.map  源码映射【https://developer.mozilla.org/zh-CN/docs/Tools/Debugger/How\_to/Use\_a\_source\_map】,以及二进制文件的 .wat 文本表示形式。文本表示形式是为了供人阅读,但现在我们无需阅读或理解它——使用 AssemblyScript 的目的之一就是我们不需要使用原始 WebAssembly。

启动 Node 并像其他模块一样使用编译模块。

1$ node2Welcome to Node.js v12.10.0.3Type ".help" for more information.4> const add = require('./index').add;5undefined6> add(3, 5)78

这就是从 Node 调用 WebAssembly 所需要的全部!

添加监视脚本

为了便于开发,我建议你在每次更改源代码时都用 onchange【https://github.com/Qard/onchange】 自动重建模块,因为 AssemblyScript  尚不包括监视模式【https://github.com/AssemblyScript/assemblyscript/issues/624】。

1npm install --save-dev onchange

package.json 中添加一个 asbuild:watch 脚本。包含 -i 标志即可在运行命令后立即运行初始构建。

1{2  "scripts": {3    "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug",4    "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize",5    "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized",6    "asbuild:watch": "onchange -i 'assembly/**/*' -- npm run asbuild"7  }8}

现在你可以运行 asbuild:watch,而不必不断地重新运行 asbuild

性能

让我们写一个基本的基准测试,用来了解究竟可以获得什么样的性能提升。WebAssembly 的专长是处理诸如数字计算之类的 CPU 密集型任务,所以我们用一个函数来确定整数是否为质数。

我们的参考实现如下所示。这是一种幼稚的暴力解决方案,因为我们的目标是执行大量计算。

 1function isPrime(x) { 2    if (x < 2) { 3        return false; 4    } 5 6    for (let i = 2; i < x; i++) { 7        if (x % i === 0) { 8            return false; 9        }10    }1112    return true;13}

等效的 AssemblyScript 版本仅需要一些类型注释:

 1function isPrime(x: u32): bool { 2    if (x < 2) { 3        return false; 4    } 5 6    for (let i: u32 = 2; i < x; i++) { 7        if (x % i === 0) { 8            return false; 9        }10    }1112    return true;13}

我们将使用 Benchmark.js【https://benchmarkjs.com/】。

1npm install --save-dev benchmark

创建benchmark.js

 1const Benchmark = require('benchmark'); 2 3const assemblyScriptIsPrime = require('./index').isPrime; 4 5function isPrime(x) { 6    for (let i = 2; i < x; i++) { 7        if (x % i === 0) { 8            return false; 9        }10    }1112    return true;13}1415const suite = new Benchmark.Suite;16const startNumber = 2;17const stopNumber = 10000;1819suite.add('AssemblyScript isPrime', function () {20    for (let i = startNumber; i < stopNumber; i++) {21        assemblyScriptIsPrime(i);22    }23}).add('JavaScript isPrime', function () {24    for (let i = startNumber; i < stopNumber; i++) {25        isPrime(i);26    }27}).on('cycle', function (event) {28    console.log(String(event.target));29}).on('complete', function () {30    const fastest = this.filter('fastest');31    const slowest = this.filter('slowest');32    const difference = (fastest.map('hz') - slowest.map('hz')) / slowest.map('hz') * 100;33    console.log(`${fastest.map('name')} is ~${difference.toFixed(1)}% faster.`);34}).run();

在我的机器上,运行 node benchmark 时得到了以下结果:

1AssemblyScript isPrime x 74.00 ops/sec ±0.43% (76 runs sampled)2JavaScript isPrime x 61.56 ops/sec ±0.30% (64 runs sampled)3AssemblyScript isPrime is ~20.2% faster.

请注意,这个测试是一个 microbenchmark【https://stackoverflow.com/a/2842707/1481479】,我们应该谨慎阅读。

对于一些更多的 AssemblyScript 基准测试,我建议你查看 WasmBoy 基准测试【https://wasmboy.app/benchmark/】 和波动方程式基准测试【https://jtiscione.github.io/webassembly-wave/index.html】。

加载模块

接下来,在网站中使用我们的模块。

先创建 index.html

 1<!DOCTYPE html> 2<html> 3    <head> 4        <meta charset="utf-8" /> 5        <title>AssemblyScript isPrime demo</title> 6    </head> 7    <body> 8        <form id="prime-checker"> 9            <label for="number">Enter a number to check if it is prime:</label>10            <input name="number" type="number" />11            <button type="submit">Submit</button>12        </form>1314        <p id="result"></p>1516        <script src="demo.js"></script>17    </body>18</html>

再创建 demo.js。加载 WebAssembly 模块有多种方式【https://developers.google.com/web/updates/2018/04/loading-wasm】,但是最有效的方法是通过使用 WebAssembly.instantiateStreaming 函数以流的方式编译和实例化。请注意,如果 assertion【https://docs.assemblyscript.org/basics/environment#utility】 失败的话,我们需要提供 abort 函数【https://docs.assemblyscript.org/details/debugging#overriding-abort】。

 1(async () => { 2    const importObject = { 3        env: { 4            abort(_msg, _file, line, column) { 5                console.error("abort called at index.ts:" + line + ":" + column); 6            } 7        } 8    }; 9    const module = await WebAssembly.instantiateStreaming(10        fetch("build/optimized.wasm"),11        importObject12    );13    const isPrime = module.instance.exports.isPrime;1415    const result = document.querySelector("#result");16    document.querySelector("#prime-checker").addEventListener("submit", event => {17        event.preventDefault();18        result.innerText = "";19        const number = event.target.elements.number.value;20        result.innerText = `${number} is ${isPrime(number) ? '' : 'not '}prime.`;21    });22})();

现在安装 static-server【https://github.com/nbluis/static-server】。因为要使用`WebAssembly.instantiateStreaming`,我们需要创建服务,该模块需要使用 MIME type【https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics\_of\_HTTP/MIME\_types】 的  application/wasm

1npm install --save-dev static-server

将脚本添加到 package.json 中。

1{2  "scripts": {3    "serve-demo": "static-server"4  }5}

运行 npm run serve-demo 并在浏览器中打开 localhost URL。提交表单中的数字,你将收到一条消息,指出该数字是否为素数。现在,我们已经实现了从用 AssemblyScript 编码到在网站中实际使用的整个过程。

结论

WebAssembly 以及通过 AssemblyScript 的扩展,不会使每个网站都神奇地变得更快,但是这并不重要。WebAssembly 之所以令人兴奋,是因为它可以使更多的应用在 Web 变得中可行。

类似地,AssemblyScript 使更多开发人员可以使用 WebAssembly,这使我们很容易默认使用 JavaScript,但是当需要大量运算工作时,可以用 WebAssembly。

原文:https://blog.logrocket.com/the-introductory-guide-to-assemblyscript/

AssemblyScript 入门指南[每日前端夜话0xEB]

下面夹杂一些私货:也许你和高薪之间只差这一张图

2019年京程一灯课程体系上新,这是我们第一次将全部课程列表对外开放。

愿你有个好前程,愿你月薪30K。我们是认真的 !

AssemblyScript 入门指南[每日前端夜话0xEB]

在公众号内回复“体系”查看高清大图

长按二维码,加大鹏老师微信好友

拉你加入前端技术交流群

唠一唠怎样才能拿高薪

AssemblyScript 入门指南[每日前端夜话0xEB]

AssemblyScript 入门指南[每日前端夜话0xEB]

往期精选

小手一抖,资料全有。长按二维码关注前端先锋,阅读更多技术文章和业界动态。

AssemblyScript 入门指南[每日前端夜话0xEB]

本文分享自微信公众号 - 前端先锋(jingchengyideng)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Java修道之路,问鼎巅峰,我辈代码修仙法力齐天
<center<fontcolor00FF7Fsize5face"黑体"代码尽头谁为峰,一见秃头道成空。</font<center<fontcolor00FF00size5face"黑体"编程修真路破折,一步一劫渡飞升。</font众所周知,编程修真有八大境界:1.Javase练气筑基2.数据库结丹3.web前端元婴4.Jav
Stella981 Stella981
2年前
Node.js 12中的ES模块[每日前端夜话0x9E]
每日前端夜话0x9E每日前端夜话,陪你聊前端。每天晚上18:00准时推送。正文共:2552字预计阅读时间:10 分钟作者:BrianDeSousa翻译:疯狂的技术宅来源:logrocket!(https://oscimg.oschina.net/oscnet/2ccaf94cecd3
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这