Search code examples
pythonpython-3.xtypescriptconcurrent.futures

Equivalent of js then() in python?


In Typescript I'm used to writing async code like this:

async function foo()  // returns a promise
    return new Promise<string>( resolve, reject) {
       resolve('Hello!');
    });

async function bar() {
  s: string  = await foo();
}

async function baz() {
   foo().then((s: string) { alert(s); }

How would I go about doing this in python (>= 3.7.0)? I guess this is correct:

async def bar:
    await s = foo()

But what about the python equivalents for foo() and baz()? How would I write them? Should I be using concurrent.futures.Future objects? If so, how?


Solution

  • Python's async support is syntactic sugar to hide awaitables, not to expose them. As such, one generally does not explicitly use the equivalent of a JS Promise – in most async frameworks a Future or Task – but the native language primitives.

    async def foo():
        return "Hello!"  # async function returns directly
    
    async def bar():
        s = await foo()  # async function is await'ed
    
    async def baz():
        print(await foo())  # await function to "then" use its result
    

    The above code are just native primitives, and as such valid in all Python async frameworks, be it asyncio, trio, curio or others. Explicitly interacting with a Promise to add callbacks is not supported by all async frameworks – in fact, many are explicitly designed to reject this notion.


    The asyncio framework allows to add callbacks to both Future and Task objects, which represent first-class concurrent actions (similar to a thread). Such operations are usually not async themselves, and can be done by regular functions.

    import asyncio
    
    def qux():
        footure = asyncio.create_task(foo())
        footure.add_done_callback(lambda foot: print(f"The future said {foot.result()}"))
        return footure
    

    Note that while asyncio exposes this functionality, it is considered exclusive to low-level use-cases.

    add_done_callback(callback, *, context=None)

    Add a callback to be run when the Task is done.

    This method should only be used in low-level callback-based code.