Skip to content

Add support for async / await #131

Closed

Description

@JdeH

Maybe await JS7...

Activity

  1. self-assigned this
    on Oct 12, 2016
  2. pjbonestroo commented on Oct 29, 2016

    @pjbonestroo

    In the mean-time someone migth use functions like below, to get the same behavior as async / await. Instead of await, use yield.

    # generator-function to Promise to get async-await behaviour by using 'yield' for 'await'
    def genToProm(generatorFunction, *args):
        def promiseFunction(resolve, reject):
            gen = generatorFunction(*args) # make generator from generator-function
            def step(nextF):
                next = None
                try:
                    next = nextF()
                except Exception as e: # finished with failure, reject the promise
                    reject(e)
                    return
                if next.done: # finished with success, resolve the promise
                    resolve(next.value)
                    return
                # not finished, chain off the yielded promise and `step` again
                Promise.resolve(next.value).then(
                    lambda v: step(lambda: gen.js_next(v)),
                    lambda e: step(lambda: gen.throw(e)))
            step(lambda: gen.js_next(None))
        return __new__(Promise(promiseFunction))
    
    # gives an promise with as result the parameter function result
    # function will be started after at least *delay* milliseconds
    def async(delay, func, *args):
        def promiseFunction(resolve, reject):
            def timeoutFunction():
                try:
                    resolve(func(*args))
                except Exception as e:
                    reject(e)
            setTimeout(timeoutFunction, delay)
        return __new__(Promise(promiseFunction))
    
    

    One can use these functions like below:

    def getFirstName():
        return async(1000, lambda: 'isaac')
    
    def getSecondName():
        #raise Exception("Cannot generate newton")
        return async(1000, lambda: 'newton')
    
    def sayHello(startValue):
        console.log(str(startValue))
        a = yield getFirstName()
        b = yield getSecondName()
        console.log(a, b)
    
    prom = genToProm(sayHello, "Hello!!")
    prom.then(lambda: console.log("Finished")).catch(lambda e: console.log(e))
    

    Kind regards,
    Pieter Jan
    (if you don't like this message at this place, feel free to remove if possible. I'm just enthousiastic about Transcrypt and want to share my experiments)

  3. axgkl commented on Oct 30, 2016

    @axgkl
    Contributor

    there is a go to javascript transpiler where we could learn from, they fully support goroutines, see here how they are doing it (high level) https://github.com/gopherjs/gopherjs#goroutines

  4. JdeH commented on Nov 4, 2016

    @JdeH
    CollaboratorAuthor

    Postponed until at least supported by Google Closure, and preferably also by a significant part of the newest browser versions.

  5. pjbonestroo commented on Dec 2, 2016

    @pjbonestroo

    Chrome now supports the async and await JavaScript keywords.
    See Software-update: Google Chrome 55.0.2883.75
    https://tweakers.net/downloads/39301/google-chrome-550288375.html
    https://developers.google.com/web/fundamentals/getting-started/primers/async-functions

  6. JdeH commented on Dec 3, 2016

    @JdeH
    CollaboratorAuthor
  7. JdeH commented on Jun 16, 2017

    @JdeH
    CollaboratorAuthor

    Seems this should come to life again by now...

  8. mmjee commented on Jun 19, 2017

    @mmjee

    https://caniuse.com/#feat=async-functions

    Async functions are now supported in majority of browsers (AFAICT, 66%)

    It should be very simple to implement, if Transcrypt sees a function is a asyncio.coroutine (or an async function), it just can put 'async ' before 'function blah(blah, blah, blah)', and emit await where an async function is 'await'-ing a value.

    Pardon me, it's midnight, english.

    async def test():
        v = await someFunctionThatReturnsPromise()
        pass
    var test = async function test() {
        var v = await someFunctionThatReturnsPromise();
    }

    ^ Fairly equivalent

  9. mmjee commented on Jun 28, 2017

    @mmjee

    I've been stuck on this for a long time, been using Bluebird.coroutine for a while now, but I do hate using generators for a thing they weren't made for, I'd really appreciate the syntactic sugar for async def.

  10. JdeH commented on Jun 28, 2017

    @JdeH
    CollaboratorAuthor

    That certainly looks simple enough.
    Will delve into this right now...

  11. JdeH commented on Jul 6, 2017

    @JdeH
    CollaboratorAuthor

    A first stab, global functions only.
    This should now work.

    __pragma__ ('js', '{}', '''
        function resolveAfter2Seconds (x) {
          return new Promise (resolve => {
            setTimeout (() => {
              resolve (x);
            }, 2000);
          });
        }
    ''')
    
    async def f ():
      print (await resolveAfter2Seconds(10))
    
    f ()
    
    

    Note that it requires the -e 6 switch.
    Main gotcha was how to get Google Closure to accept ES8 code.

  12. JdeH commented on Jul 7, 2017

    @JdeH
    CollaboratorAuthor

    Following code from development/manual_tests/async_await now works correctly:

    
    from org.transcrypt.stubs.browser import __pragma__, __envir__
    
    # Note that CPython will ignore all pragma's
    
    
    
    # Provide waitAWhile for Transcrypt
    
    __pragma__ ('js', '{}', '''
        function waitAWhile (aTime, asio) {
          return new Promise (resolve => {
            setTimeout (() => {
              resolve (aTime);
            }, 1000 * aTime);
          });
        }
    ''')
    
    
    
    # Provide waitAWhile for CPython
    
    __pragma__ ('skip') # Compile time, needed because import is done compile time
    
    import asyncio
    
    def waitAWhile (aTime, asio):
        return asio.sleep (aTime)
            
    __pragma__ ('noskip')
    
    
        
    # Actual code to be tested    
        
    async def f (waw, asio):
        print ('f0')
        await waw (2, asio)
        print ('f1')
     
    class C:
        def __init__ (self):
            self.aTime = 2
            
        async def g (self, waw, asio):
            print ('g0')
            await waw (self.aTime, asio)
            print ('g1')
    
    c = C ()
        
    
    # Just call async functions for Transcrypt, since in the browser JavaScript is event driven by default
        
    if __envir__.executor_name == __envir__.transpiler_name:
        f (waitAWhile, None)
        c.g (waitAWhile, None)
        c.g (waitAWhile, None)
        f (waitAWhile, None)
        
        
        
    # Create event loop and tasks for CPython, since it isn't event driven by default
        
    else:
        eventLoop = asyncio.get_event_loop ()
        tasks = [
            eventLoop.create_task (f (waitAWhile, asyncio)),
            eventLoop.create_task (c.g (waitAWhile, asyncio)),
            eventLoop.create_task (c.g (waitAWhile, asyncio)),
            eventLoop.create_task (f (waitAWhile, asyncio)),
        ]
    
        waitingTasks = asyncio.wait (tasks)
        eventLoop.run_until_complete (waitingTasks)
        eventLoop.close ()
    
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions