Having used both QuickJS and Duktape, I have to say that QuickJS is a lot better. Mostly because it's faster and has newer language features. QuickJS has full support for ES2020, whereas Duktape is on ES2015. I guess Duktape is a little smaller, but that's the only advantage I found.
> Duktape is a little smaller, but that's the only advantage I found.
It's not actually smaller; Duktape is about 4MB source files while QuickJS is about 2.7 MB. But Duktape has a nice C API similar to Lua. And QuickJS requires a recent C compiler whereas Duktape is happy with C89.
For some reason I remember the compiled size for Duktape being smaller, but I could be misremembering. It's been a few years since I've used both libraries.
Bellard has an evaluation on his website where the executable size of QuickJS is bigger than Duktape: https://bellard.org/quickjs/bench.html. Both were compiler with gcc 4.9.2. I don't know the reason for the difference (both have large unicode tables etc.).
I’ve spent quite some time recently wrangling Unicode tables, so a quick note: unless you consciously go for performance over size (e.g. the Windows SBCS code pages use a 65536-entry lookup table for encoding, each), Unicode property tables are not that large.
With general category, a basic[1] set of properties, and canonical normalization, you can get away with about 30K for the whole lot without much of a problem, and probably less than that if you use a sorted inversion list instead of a trie for binary properties (both Plan 9 / libutf and Duktape do this IIRC, while QuickJS does something trickier I haven’t grokked yet, but it’s obviously not trying to be a speed demon there either).
Compatibility decompositions are more problematic (so. many. ideographs), I’m still at 20K for those, and I expect default casing and case folding will cost about that much as well. Maybe you also want some other properties (breaks? bidi class? script?). So let’s say 60K at best, 90K at worst, total.
Overall, a considerable but not catastrophic contribution to Duktape’s 330K (as quoted in your link) and even less of a problem for QuickJS’s 620K. And that is for tables that you can run against—if you’re willing to sacrifice runtime memory consumption for disk / wire size, you can do substantially better[2].
(These were rough estimates from experience. The actual figure for QuickJS turns out to be 37K, so I was a bit too pessimistic; I can’t compile Duktape right now, but it’s probably smaller given it can’t even normalize[3].)
Character names, collation, or locales / tailoring would multiply the size severalfold, but I think none of the small engines here do any of that (although an engine that wanted ECMA-402 internationalization would need all of it and more).
That's interesting, thanks. I'm currently using the trie and properties table from https://github.com/rochus-keller/Qt-4.8.7/blob/master/src/co... for a new open source project of mine; the source file is 204k and the compiler produces an 68k object file from it.
It’s really good as an embedded JS engine. Like let’s say you want to make an iOS app that executed JS. If you use V8 (Node’s JS engine), then you’re app is at a minimum 28M in size just from V8. If you use QuickJS, your app size increases by less than 1M.
I don’t think you can create native bindings in WebKit. You can only interact with something like WKWebView using serializable messages. QuickJS let’s you create native objects and expose them directly to the JS API. QuickJS also let’s you get JS variables natively and control how and when things get executed.
Ah yea that’s right. Now I remember why we didn’t use JSCore. We had a cross-platform C++ library for both Android and iOS so it was better to use a single JS Engine.
I saw that recently and it gave me pause. An entire scripting engine (and JS of all things?) For permission queries. That's a lot of rope for hanging yourself in a variety of ways when all you're doing is encoding a two dimensional table of users and permissions.
Fortunately Debian's conservatism has kept them on policykit, which avoids this nonsense.
I maintain a library for using QuickJS, a JS interpreter with more modern language support, from NodeJS or the web called QuickJS-Emscripten: https://github.com/justjake/quickjs-emscripten
I'm in the middle of making a Host JavaScript environment for M4 microcontrollers using duktape as the JavaScript interpreter. The microcontroller mounts as a flash drive and you can save your JS to the board directly.
Some of the extensions look like good idea, such as extended JSON, and ignoring shebang lines (although I think that they might have wanted to make this standard).
It will be useful to have variants of loadFile and some other functions that currently deal only with UTF-8 strings:
[1] UTF-8
[2] ISO-8859-1
[3] ArrayBuffer
Currently, only urlGet has a variant using ArrayBuffer, although it would be useful to allow that for loadFile too, to avoid having to open and measure and close the file to do it by yourself.
Additionally, urlGet lacks some of the options of curl (such as whether or not to follow redirects).
Typed arrays may also be necessary for command-line arguments and environment variables and file names in some cases, where they might not be valid UTF-8 (it is not guaranteed that they will be; this depends on the file system in use, though, since some are always Unicode; however, some allow mismatched surrogates so this must also be permitted). (Node.js allows this for file names, but it seems not for command-line arguments and environment variables.) Additionally, the locale might or might not be Unicode, but even if it is, that does not necessarily mean that the other things are. Assuming that everything is UTF-8 is an invalid assumption (it might not even be text in any encoding at all; it might even be null-terminated binary data), and programs that deal with Unicode often incorrectly ignore the locale.
There are some insights/comparisons in speed and memory usage in the Frida 14.0 [0] release notes, when they switched from Duktape to QuickJS. Overall, QuickJS seems to be slightly more performant and requires about a fifth of the memory usage for the runtime.