Running JavaScript in WebAssembly with WasmEdge

WebAssembly started out as an "in-browser JavaScript replacement". The idea is to safely run high-performance applications compiled from languages ​​like C/C++ or Rust in the browser. In the browser, WebAssembly and JavaScript run side by side.

Figure 1. WebAssembly and JavaScript in the browser

With the increasing use of WebAssembly in the cloud, Wasm is now the universal runtime for cloud-native applications. Compared to Docker-like application containers, the WebAssembly runtime achieves higher performance with lower resource consumption. Common use cases for WebAssembly in the cloud include the following

However, in cloud-native application scenarios, developers often want to use JavaScript to write business applications. This means that now we have to support JavaScript within WebAssembly . Additionally, we should support calling C/C++ or Rust functions from JavaScript in the WebAssembly runtime, taking advantage of the computational efficiency of WebAssembly. The WasmEdge WebAssembly runtime is already able to do this.

Figure 2. WebAssembly and JavaScript in the cloud

WasmEdge

WasmEdge is a leading cloud-native WebAssembly runtime hosted by CNCF (Cloud Native Computing Foundation) . It is the fastest WebAssembly runtime on the market today. WasmEdge supports all standard WebAssembly extensions as well as proprietary extensions for Tensorflow inference, networking, KV storage, and image processing. Its compiler toolchain supports not only WebAssembly languages ​​such as C/C++, Rust, Swift, Kotlin and AssemblyScript, but also regular JavaScript .

WasmEdge applications can be embedded into C programs, Go programs, Rust programs, JavaScript programs, or the operating system's CLI . WasmEdge can be managed by the following tools:

You can now run JavaScript programs in serverless functions, microservices and AIoT applications powered by WasmEdge! WasmEdge can not only run normal JavaScript programs, but also allows developers to create new JavaScript APIs using Rust and C/C++ in WebAssembly's secure sandbox.

Building a JavaScript engine in WasmEdge

First, let's build a WebAssembly-based JavaScript interpreter program for WasmEdge. This program is based on QuickJS with WasmEdge extensions such as network sockets and Tensorflow inference , and is incorporated into the interpreter as a JavaScript API. First, Rust needs to be installed to build the interpreter.

If you just want to use the interpreter to run your JavaScript project, you can skip this section. Make sure you have Rust and WasmEdge installed .

Fork or clone the wasmedge-quickjs Github repos to get started. All examples in this article will be counted in wasmedge-quickjs.

$ git clone https://github.com/second-state/wasmedge-quickjs

Following the instructions in the repo, you will be able to build a JavaScript interpreter for WasmEdge.

$ `rustup target add wasm32-wasi`
$ cargo build --target wasm32-wasi --release

The WebAssembly-based JavaScript interpreter program is located in the target directory where it is built. You can now try a simple "hello world" JavaScript program ( example_js/hello.js ) that will print out command line arguments to the controller.

args = args.slice(1)
print("Hello",…args)

Run the hello.jsfile as follows. Note that on the command line --dir .:.is a local directory to allow wasmedgereading of files hello.jsin the filesystem.

$ wasmedge --dir .:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/hello.js WasmEdge Runtime
Hello WasmEdge Runtime

Next, let's try some more advanced JavaScript programs.

JavaScript networking example

The interpreter supports the WasmEdge networking socket extension so that JavaScript programs can establish HTTP connections to the Internet. Here is a JavaScript example.

let r = GET("http://18.235.124.214/get?a=123",{"a":"b","c":[1,2,3]})
print(r.status)
    
let headers = r.headers
print(JSON.stringify(headers))

let body = r.body;
let body_str = new Uint8Array(body)
print(String.fromCharCode.apply(null,body_str))

To run JavaScript in the WasmEdge runtime, run the following command in the CLI.

$ wasmedge --dir .:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/http_demo.js

You should see the HTTP GET result printed in the controller.

JavaScript Tensorflow Inference Example

The interpreter supports the WasmEdge Tensorflow lite inference extension so that JavaScript can run ImageNet models for image classification. Here is an example in JavaScript.

import {TensorflowLiteSession} from 'tensorflow_lite'
import {Image} from 'image'

let img = new Image('./example_js/tensorflow_lite_demo/food.jpg')
let img_rgb = img.to_rgb().resize(192,192)
let rgb_pix = img_rgb.pixels()

let session = new TensorflowLiteSession('./example_js/tensorflow_lite_demo/lite-model_aiy_vision_classifier_food_V1_1.tflite')
session.add_input('input',rgb_pix)
session.run()
let output = session.get_output('MobilenetV1/Predictions/Softmax');
let output_view = new Uint8Array(output)
let max = 0;
let max_idx = 0;
for (var i in output_view){
    let v = output_view[i]
    if(v>max){
        max = v;
        max_idx = i;
    }
}
print(max,max_idx)

To run JavaScript on the WasmEdge runtime, you can do the following on the CLI, rebuild the QuickJS engine using Tensorflow, and then run the JavaScript program using the Tensorflow API.

$ cargo build --target wasm32-wasi --release --features=tensorflow
... ...
$ wasmedge-tensorflow-lite --dir .:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/tensorflow_lite_demo/main.js
label:
Hot dog
confidence:
0.8941176470588236

Notice:

  • --features=tensorflowCompiler flags build a version of the QuickJS engine using the WasmEdge Tensorflow extension.
  • wasmedge-tensorflow-litePrograms are part of the WasmEdge package. It is the WasmEdge runtime with built-in Tensorflow extensions

You should now see the food names recognized by the TensorFlow lite ImageNet model.

--features=tensorflowCompiler flags build a version of the QuickJS engine using the WasmEdge Tensorflow extension. wasmedge-tensorflow-liteThe program is part of the WasmEdge software package. It is the WasmEdge runtime with built-in Tensorflow extensions.

further acceleration

The Tensorflow inference example above takes 1-2 seconds to run. This is acceptable in a web application scenario, but could be improved. Recall that WasmEdge is the fastest WebAssembly Runtime today due to its AOT (ahead of time) optimization. WasmEdge provides a wasmedgecutility to wasmcompile files into native soshared libraries. You can use wasmedgeto run sofile instead of wasmfile for faster performance.

The example below wasmedgeuses wasmedgecextended versions of and to support the WasmEdge Tensorflow extension.

$ wasmedgec-tensorflow target/wasm32-wasi/release/quickjs-rs-wasi.wasm quickjs-rs-wasi.so
$ wasmedge-tensorflow-lite --dir .:. quickjs-rs-wasi.so example_js/tensorflow_lite_demo/main.js
label:
Hot dog
confidence:
0.8941176470588236

This time the image classification task can be completed in 0.1 seconds. This is at least a 10x improvement!

soShared libraries are not portable across machines and operating systems. You should be running wasmedecand wasmedec-tensorflow.

Notes on QuickJS

Choosing QuickJS as our JavaScript engine can cause performance issues. Isn't QuickJS much slower than v8 due to lack of JIT support ? That's right! but……

First, QuickJS is much smaller than v8. In fact, it only requires 1/40 (or 2.5%) of the runtime resources that v8 consumes. You can run many more QuickJS functions than v8 functions on a single physical machine.

Second, for most business logic applications, raw performance doesn't matter. Applications may have computationally intensive tasks such as dynamic AI inference. WasmEdge allows QuickJS applications to use high-performance WebAssembly for these tasks, and adding such extension modules in v8 was not easy.

Third, it is well known that many JavaScript security problems stem from the JIT . Maybe turning off JIT in a cloud-native environment isn't such a bad idea!

what's next?

These examples demonstrate how to use the quickjs-rs-wasi.wasmJavaScript engine in WasmEdge. In addition to using the CLI, you can also use Docker/Kubernetes tooling to spin up WebAssembly applications or embed applications into your own application or framework, as we discussed earlier in this article.

In the next three articles, I'll focus on using JavaScript with Rust to get the most out of both languages.

JavaScript in cloud-native WebAssembly is still an emerging field in next-generation cloud and edge computing infrastructure. We are just getting started! If you are interested, welcome to join our WasmEdge project. You can also tell us your needs by filing a feature request issue).

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324173469&siteId=291194637