Skip to content

Instantly share code, notes, and snippets.

@MangelMaxime
Last active May 13, 2024 09:43
Show Gist options
  • Save MangelMaxime/e476b6a02021bea2bf7bb47baa79b621 to your computer and use it in GitHub Desktop.
Save MangelMaxime/e476b6a02021bea2bf7bb47baa79b621 to your computer and use it in GitHub Desktop.
Demonstrate how to use native async/await from JavaScript with haxe.
package async;
#if macro
import haxe.macro.Context;
#end
class Async {
public static macro function async(expr:haxe.macro.Expr) {
expr = Context.storeTypedExpr(Context.typeExpr(expr));
return macro untyped __js__("(async {0})", ${expr})();
}
public static macro function await(expr:haxe.macro.Expr) {
expr = Context.storeTypedExpr(Context.typeExpr(expr));
return switch (haxe.macro.Context.typeof(expr)) {
case TInst(_.toString() => "js.Promise", [t]):
var ct = haxe.macro.TypeTools.toComplexType(t);
return macro(untyped __js__("await {0}", ${expr}) : $ct);
default:
throw 'await() is only available for promises';
}
}
public static macro function asyncPromise(expr:haxe.macro.Expr) {
expr = Context.storeTypedExpr(Context.typeExpr(expr));
return macro untyped __js__("(new Promise(async {0}))", ${expr});
}
}
package async;
@:autoBuild(async.AsyncMacro.macroBuild())
class Asyncify {
}
package async;
import haxe.macro.Expr;
#if macro
import haxe.macro.Context;
#end
class AsyncMacro {
public static function macroBuild() {
var fields = Context.getBuildFields();
for (field in fields) {
function e(expr) return { expr : expr, pos : field.pos };
switch(field.kind) {
case FieldType.FFun(f):
// trace(field.name);
// trace(f.expr);
for (m in field.meta) {
switch(m.name) {
case ":async":
var ex = e(EBlock([
e(EReturn(
e(EUntyped(
e(ECall(
e(ECall(
e(EConst(CIdent("__js__"))),
[
e(EConst(CString("(async {0})"))),
e(EFunction(null,
{ args : []
, expr : f.expr
, params : []
, ret : null
}
))
]
)),
[]
))
))
))
]));
f.expr = ex;
default:
}
}
default:
}
}
return fields;
}
}
import async.Asyncify;
import async.Async;
// Here is the ouput generated by the nest program
// Start the program
// Now #1: 2018-09-05 15:05:03
// Now #2 2018-09-05 15:05:05
// Now #3 2018-09-05 15:05:05
// Now #4 2018-09-05 15:05:07
class Main {
static function main() {
        trace("Start the program");
new Runner().run();
    }
}
// Make your class extends Asyncify to use @:async on a member
class Runner extends Asyncify {
public function new() { }
// By using @:async on a member, it's becoming an async context
@:async
    public function run() {
trace("Now #1: " + Date.now().toString());
var now2 = Async.await(resolveAfter2Seconds());
trace("Now #2 " + now2);
// We can also create a local async context by using Async.async
Async.async(function() {
var now4 = Async.await(resolveAfter2Seconds());
trace("Now #4 " + now4);
});
trace("Now #3 " + Date.now().toString());
    }
static function resolveAfter2Seconds() {
        return new js.Promise(function(resolve, reject) {
            untyped __js__("setTimeout")(function() {
                resolve(Date.now().toString());
            }, 2000);
        });
    }
}
@maxless
Copy link

maxless commented Dec 1, 2020

Thanks for the heads up, I missed this one in my research.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment