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

Seems async Task doesn't work #5376

Closed
MihaelIsaev opened this issue Apr 8, 2023 · 6 comments
Closed

Seems async Task doesn't work #5376

MihaelIsaev opened this issue Apr 8, 2023 · 6 comments
Labels
bug Something isn't working

Comments

@MihaelIsaev
Copy link

Description

I'm trying to execute async code wrapped into Task but it never called.

Steps to reproduce

  1. Create new carton project using carton init
  2. Use the following example
@main
public struct CartonApp {
    public private(set) var text = "Hello, World!"

    public static func main() {
        print(CartonApp().text)
        Task {
            print("async Task works") // this never calls
        }
    }
}

Expected behavior

async Task works should be printed into console

Environment

  • Swift compiler version info
SwiftWasm Swift version 5.7.1 (swiftlang-5.7.1)
Target: arm64-apple-darwin21.6.0
  • Xcode version info
Xcode 14.1
Build version 14B47b
  • Deployment target:
WASI

@kateinoigakukun

@MihaelIsaev MihaelIsaev added the bug Something isn't working label Apr 8, 2023
@MihaelIsaev
Copy link
Author

I just tried to use JSClosure.async which doesn't work.
Code inside of Task inside of synchronous JSClosure doesn't work also. (it is same as JSClosure.async)
Then I tried to create new carton project just to check if it works there, but unfortunately it doesn't.

The only place where Task works is

static func main() async {
    Task {
        print("🔆🔆🔆🔆🔆🔆") // works
    }
}

But it never works anywhere later.

And btw it throws this in the WebInspector console
Screenshot 2023-04-08 at 19 53 04

Not sure if I'm missing something.
@kateinoigakukun please help 🙏

@MihaelIsaev
Copy link
Author

MihaelIsaev commented Apr 8, 2023

One more example

import JavaScriptKit

@main
public struct CartonApp {
    public private(set) var text = "Hello, World!"

    public static func main() async {
        print(CartonApp().text)
        if let docObj = JSObject.global.document.object, let bodyObj = JSObject.global.document.jsValue.body.object {
            var button = JSObject.global.document.createElement.function?.callAsFunction(this: docObj, "button").jsValue
            button?.innerText = "Click me".jsValue
            JSObject.global.document.jsValue.body.appendChild.function?.callAsFunction(this: bodyObj, button)
            if let buttonObj = button?.object {
                button?.addEventListener.function?.callAsFunction(this: buttonObj, "click", JSClosure({ args in
                    print("clicked") // works
                    Task {
                        print("clicked inside of Task") // never called
                    }
                    return .undefined
                }))
            }
        }
    }
}

JSClosure.async doesn't work at all

button?.addEventListener.function?.callAsFunction(this: buttonObj, "click", JSClosure.async({ args in
    print("clicked async") // never called
    return .undefined
}))

@yonihemi
Copy link
Member

yonihemi commented Apr 9, 2023

Thanks for reporting. This code however won't run as you expect, even on macOS:

@main
public struct CartonApp {
    public private(set) var text = "Hello, World!"

    public static func main() {
        print(CartonApp().text)
        Task {
            print("async Task works") // this never calls
        }
    }
}

Expected behavior

async Task works should be printed into console

It's a misunderstanding of the main function's lifetime. Once you start the task, the synchronous context reaches its end and there's nothing telling it to keep alive.
On other platform you can use CFRunLoopRun() to signal 'keep my process alive', but that's not supported in SwiftWasm.
The correct way to achieve that for the main function would be changing the signature from public static func main() to public static func main() async, remove the task and directly use async code. This is supported in latest SwiftWasm toolchains.

@MihaelIsaev
Copy link
Author

@yonihemi Thank you for the reply. Could you please help with JSClosure.async ? It doesn't work.

import JavaScriptKit

@main
public struct CartonApp {
    public private(set) var text = "Hello, World!"

    public static func main() async {
        print(CartonApp().text)
        if let docObj = JSObject.global.document.object, let bodyObj = JSObject.global.document.jsValue.body.object {
            var button = JSObject.global.document.createElement.function?.callAsFunction(this: docObj, "button").jsValue
            button?.innerText = "Click me".jsValue
            JSObject.global.document.jsValue.body.appendChild.function?.callAsFunction(this: bodyObj, button)
            if let buttonObj = button?.object {
                button?.addEventListener.function?.callAsFunction(this: buttonObj, "click", JSClosure.async({ args in
                    print("clicked async") // never called
                    return .undefined
                }))
            }
        }
    }
}

@MaxDesiatov
Copy link

MaxDesiatov commented Apr 11, 2023

I don't see calls to JavaScriptEventLoop.installGlobalExecutor() in your sample code, per JSKit documentation in its README.md.

@MihaelIsaev
Copy link
Author

That's awesome, that's exactly what I missed!🔥 Thank you very much for pointing me @MaxDesiatov I appreciate it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants