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

 async/await support #1272

Open
opichals opened this issue Nov 6, 2017 · 8 comments
Open

 async/await support #1272

opichals opened this issue Nov 6, 2017 · 8 comments

Comments

@opichals
Copy link
Contributor

opichals commented Nov 6, 2017

As there is Promise support. How difficult would be to add this as well?

A brief explanation is available at http://2ality.com/2016/02/async-functions.html.

The spec (ES2017) is available at https://tc39.github.io/ecma262/#sec-async-function-objects.

@gfwilliams
Copy link
Member

I had wondered about this - but it's actually pretty difficult to do because of the way Espruino works... It's got to be able to completely stop execution and back out of the execution stack, and then resume from where it left off.

@vshymanskyy
Copy link
Contributor

babel should be able to translate async/await into normal js code, just need to find proper configuration for Espruino...

@vshymanskyy
Copy link
Contributor

vshymanskyy commented Feb 28, 2018

Ok, I was actually able to get async/await working on Espruino (using Babel transpiler and some hacking).
Here is a full example: https://github.com/vshymanskyy/espruino-await
Looks pretty usable, but a native implementation would be so much better ;)
What do you think?

@opichals
Copy link
Contributor Author

but it's actually pretty difficult to do because of the way Espruino works...

I haven't really looked into it but my naive thinking would lead me to try to do 'live' regenerator-like stuff in the interpreter. This is just a basic idea so please bare with me here :)

Whenever the code is using the await keyword Espruino would live-transpile the lines so it would work as if it was replaced with Promise use. For example for

const makeRequest = async () => {
  await callAPromise()
  throw new Error("oops");
}

It would make it internally interpret something like the following

const makeRequest = () => {
  return callAPromise()
    .then(() => {
      throw new Error("oops");
    })
}

@gfwilliams
Copy link
Member

If it were just in a straight bit of code it'd be pretty easy, but it's how you deal with await in things like FOR and IF that's the problem :(

@opichals
Copy link
Contributor Author

opichals commented Jun 3, 2018

await in things like FOR and IF that's the problem

@gfwilliams Again, I haven't found anything specific... This http://blog.ministryofprogramming.com/async-await-and-conditional-promises/ doesn't spark any light for me as for why it is a problem. Perhaps there are some Espruino implementation details that make it obvious... could you please point me to some code to study more stuff to 'get it'? Thanks! :)

@gfwilliams
Copy link
Member

Compile for linux, then run some code in Espruino in GDB and step through execution. The issue is that Espruino doesn't use bytecode like a 'normal' interpreter. Quite a bit of state is stored in the main execution stack - so when the interpreter stops execution that would all disappear.

You'd have to come up with a way of skipping to the correct point in the code, but also you'd have to modify the parsing of every loop/if/switch/etc such that it could stop execution, save its current state to a JsVar and then restart. It'd be a nightmare.

It's such an upheaval that probably the most sane solution is to actually rewrite the interpeter to use bytecode (well, this) instead, then you'd get a huge performance boost too. We could create a second parser that just handled a subset of JS, then it'd run through and would compile if it could - otherwise we'd fall back to the old parser.

@idobh2
Copy link

idobh2 commented Mar 6, 2023

If anyone ever reaches here :)
After the 2 fixes @gfwilliams just introduced -c512aa5 & bdadb3c - async/await are transpiling great to ES5, and working well.
I'm using @swc/core to to it, with the following sequence:

import { minify, bundle, transform } from "@swc/core";
import path from "path";

// bundle
const { ["index.ts"]: { code: bundled } } = await bundle({
	entry: path.resolve(__dirname, "src/index.ts"),
});

// transpile to es5
const { code: transformed } = await transform(bundled, {
	jsc: {
		target: "es5", // this is the actual magic
	}
});

// minify
const { code } = await minify(transformed, {
	compress: true,
});

// code is what you push to the espruino device

I'm pretty sure tsc will result in similar working code as well, but haven't tested it

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

No branches or pull requests

4 participants