Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add queueMicrotask #106

Merged
merged 1 commit into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ test: build
$(QJS) tests/test_loop.js
$(QJS) tests/test_std.js
$(QJS) tests/test_worker.js
$(QJS) tests/test_queue_microtask.js

test262: build
$(RUN262) -m -c test262.conf -a
Expand Down
17 changes: 17 additions & 0 deletions quickjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -33745,6 +33745,22 @@ static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
return JS_NewBool(ctx, res);
}

static JSValue js_microtask_job(JSContext *ctx,
int argc, JSValueConst *argv)
{
return JS_Call(ctx, argv[0], ctx->global_obj, 0, NULL);
}

static JSValue js_global_queueMicrotask(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (check_function(ctx, argv[0]))
return JS_EXCEPTION;
if (JS_EnqueueJob(ctx, js_microtask_job, 1, &argv[0]))
return JS_EXCEPTION;
return JS_UNDEFINED;
}

/* Object class */

static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
Expand Down Expand Up @@ -45683,6 +45699,7 @@ static const JSCFunctionListEntry js_global_funcs[] = {
JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ),
JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
JS_CFUNC_DEF("queueMicrotask", 1, js_global_queueMicrotask ),

JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ),
JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ),
Expand Down
84 changes: 84 additions & 0 deletions tests/test_queue_microtask.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
function assert(actual, expected, message) {
if (arguments.length == 1)
expected = true;

if (actual === expected)
return;

if (actual !== null && expected !== null
&& typeof actual == 'object' && typeof expected == 'object'
&& actual.toString() === expected.toString())
return;

throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" +
(message ? " (" + message + ")" : ""));
}

function assert_throws(expected_error, func)
{
var err = false;
try {
func();
} catch(e) {
err = true;
if (!(e instanceof expected_error)) {
throw Error("unexpected exception type");
}
}
if (!err) {
throw Error("expected exception");
}
}

function assert_array_equals(a, b) {
if (!Array.isArray(a) || !Array.isArray(b))
return assert(false);

assert(a.length === b.length);

a.forEach((value, idx) => {
assert(b[idx] === value);
});
}

// load more elaborate version of assert if available
try { std.loadScript("test_assert.js"); } catch(e) {}

function test_types() {
assert_throws(TypeError, () => queueMicrotask(), "no argument");
assert_throws(TypeError, () => queueMicrotask(undefined), "undefined");
assert_throws(TypeError, () => queueMicrotask(null), "null");
assert_throws(TypeError, () => queueMicrotask(0), "0");
assert_throws(TypeError, () => queueMicrotask({ handleEvent() { } }), "an event handler object");
assert_throws(TypeError, () => queueMicrotask("window.x = 5;"), "a string");
}

function test_async() {
let called = false;
queueMicrotask(() => {
called = true;
});
assert(!called);
}

function test_arguments() {
queueMicrotask(function () { // note: intentionally not an arrow function
assert(arguments.length === 0);
}, "x", "y");
};

function test_async_order() {
const happenings = [];
Promise.resolve().then(() => happenings.push("a"));
queueMicrotask(() => happenings.push("b"));
Promise.reject().catch(() => happenings.push("c"));
queueMicrotask(() => {
assert_array_equals(happenings, ["a", "b", "c"]);
});
}

test_types();
test_async();
test_arguments();
test_async_order();