Deno: Support top-level await

Created on 7 Aug 2018  路  37Comments  路  Source: denoland/deno

Most helpful comment

Top level await has gone Stage 3. That means that the TypeScript team should be willing to implement it now.

All 37 comments

If we wanted this to work while we are waiting on TC39/TypeScript, we would have to do a bit of _hackery_.

When emitting a module with TLA, we would have to specifically ignore the diagnostic error related to that. TypeScript always emits, it is _us_ who then chooses to throw. I _might_ be a good idea to actually log a warning, since when TLA arrives, it could be a different behaviour to what we would have.

Then we would have to modify the AMD factory function to be async and deal with awaiting the promise resolution returned from that factory before we consider the module "resolved".

The drawback, like the module specifiers ending in .ts, we won't be able to get any of the editors to accept this code... so while it will run properly under deno, it won't look pretty in editors.

https://github.com/tc39/proposal-top-level-await#optional-constraint-top-level-await-can-only-be-used-in-modules-without-exports
Potentially it will be easier to do with this restriction. We only really need it for "main" scripts.

TC39 start promoting it.
Do we want to be part of it?
https://github.com/tc39/proposal-top-level-await/issues/42

Well, one member of TC39 is trying to get it moving again. I am not sure we can really add anything to it. The biggest challenge is that they need to address the functional challenge that top-level await and how modules are evaluated and as Ry mentioned above, the optional restriction would make it a lot easier, but this is really needs the implementors to figure out how to do it, versus adding another voice to the mix.

Top level await has gone Stage 3. That means that the TypeScript team should be willing to implement it now.

A V8 issue has been created for this https://bugs.chromium.org/p/v8/issues/detail?id=9344

The TypeScript team are indicating that it will be challenging to downemit and are considering not allowing a downemit. That is find from our perspective, but that "problem" continues to delay them addressing the issue.

TLA is scheduled for TS 3.7 as well (early-November): microsoft/TypeScript#33352

Deno v0.19 has integrated the changes from V8 and has a test demonstrating TLA.

However this is JS only support. We still need TS to not barf on TLA syntax. Therefore I'm leaving this issue open until we have a corresponding tests/top_level_await.ts.

That should be doable without ignoring error codes with TS 3.7 on Nov 5th.

@kitsonk In this latest TS 3.7 announcement, there is no indication that there will be any support for TLA by Nov 5th.

That is the beta, and the announcement is what is in the beta. The iteration plan mentioned above still lists it. I am sure Ry and I will chat to the team about it next week at TSConf.

In case people are following this, here's v8 issues for top-level for-await (not merged yet):

https://bugs.chromium.org/p/v8/issues/detail?id=9817
https://bugs.chromium.org/p/v8/issues/detail?id=9825

Also, I had a chat with Daniel R, PM on TypeScript team, and TLA won't make TypeScript 3.7. It simply causes us to ignore the error message in Deno and will show it as invalid in editors, though it will run fine under Deno.

In this latest TS 3.7 announcement, there is no indication that there will be any support for TLA by Nov 5th.

guess I was right then..
did Daniel R give a reason why it won't be included?

Yes, not enough time in the team. I think some of the other features took longer than they anticipated.

Actually, re-reading those commits above I think top-level for-await is in recent V8 versions. IIRC this means we can support it in ts easily once we upgrade V8.

I see that TypeScript now has first release with Top Level Await at 3.8. Does this help the progress of TLA in Deno?

Deno has TLA. You are commenting on a closed issue.

Thanks.

Deno has TLA. You are commenting on a closed issue.

This example seems to not work :

function add(a: any,b: any,c: any): any{
    if(a+b>10){
        return c("My error",a+b);
    }else{
        return c(null, a+b);
    }
}

try{

 let t = await (async()=>{
    return add(4,5,(e: any, r: any)=>{
        if(e) throw e;
        return r;   
    });
 })();
 console.log(t);
}catch(e){
console.log("Yes! caught error from call back: ", e);
}

Gives me this error:
error TS2304: Cannot find name 'await'.

@anuragvohraec this is a TypeScript problem, and the error is a mis-leading... because you don't have any imports or exports in the module, TypeScript is treating this like a script instead of a module. This is causing the parsing in the try block to be a bit off, and instead of telling you that the module isn't a module error, it is giving you this strange error.

To work around the issue just add the following at the start or the end of the module:

export {};

To work around the issue just add the following at the start or the end of the module:

export {};

still same error :

export {};

function add(a: any,b: any,c: any): any{
    if(a+b>10){
        return c("My error",a+b);
    }else{
        return c(null, a+b);
    }
}

try{

 let t = await (async()=>{
    return add(4,5,(e: any, r: any)=>{
        if(e) throw e;
        return r;   
    });
 })();
 console.log(t);
}catch(e){
console.log("Yes! caught error from call back: ", e);
}

@anuragvohraec - Pardon my N00b question, but when would you use the (async(){...})() in real world logic in Deno?

From my understanding, all functions in Deno are implicitly async and I'm not sure if this makes this async()... methodology redundant?

No, not all functions in are implicitly async. Only the global scope (so the top level of a module outside of a function scope) and all function scopes declared with the async keyword.

await foo() // valid here

function test1() {
  await foo() // invalid here
}

async function test2() {
  await foo() // valid here
}

More info on top level await: https://v8.dev/features/top-level-await

@lucacasonato - Thanks, that makes sense.

I found a good example explaining the use of async()=> here.

@anuragvohraec - Here is a tweak to your code that works for me:

function add(a: any,b: any,c: any): any{
    if(a+b>10){
        return c("My error",a+b);
    }else{
        return c(null, a+b);
    }
}

(async()=>{
    try{
        let t = await (async()=>{
            return add(4,5,(e: any, r: any)=>{
                if(e) throw e;
                return r;   
            });
        })();
        console.log(t);
    }catch(e){
        console.log("Yes! caught error from call back: ", e);
    }
})()

@anuragvohraec it is a TypeScript lexing issue. Upstream bug filed: https://github.com/microsoft/TypeScript/issues/38483.

@anuragvohraec - Pardon my N00b question, but when would you use the (async(){...})() in real world logic in Deno?

The real world example for this will be to convert a call back based asynchronous function be converted to async await based without using a Promise API.

If you see my example:

function add(a: any,b: any,c: any): any{
    if(a+b>10){
        return c("My error",a+b);
    }else{
        return c(null, a+b);
    }
}

try{

 let t = await (async()=>{
    return add(4,5,(e: any, r: any)=>{
        if(e) throw e;
        return r;   
    });
 })();
 console.log(t);
}catch(e){
console.log("Yes! caught error from call back: ", e);
}

c is a callback function.
I was trying to use a IIFE to convert my call back back based asychronous function to an async-await based function (without using an explicit Promise API).

No, not all functions in are implicitly async. Only the global scope (so the top level of a module outside of a function scope) and all function scopes declared with the async keyword.

await foo() // valid here

function test1() {
  await foo() // invalid here
}

async function test2() {
  await foo() // valid here
}

The code I have shared do not commits any mistake mentioned in your code samples.

The code I have shared do not commits any mistake mentioned in your code samples.

@anuragvohraec I don't think @lucacasonato was complaining about your code, but was just trying to inform @JavaScriptDude on how async/await works. Your code is valid JavaScript, and should be valid TypeScript but TypeScript has a bug.

is TLA supported in deno REPL?

I cant seem to get the following to work.

using Deno v.1.0.0

$ deno
> console.log(await Promise.resolve('Success'))

It just seems to await indefinitely without outputting anything or allowing me to input any further commands.

@somombo I believe #3700 is tracking the addition of top-level await to the REPL. For me (1.2.0 and 1.3.0) using top-level await in the REPL throws an error:

Uncaught SyntaxError: await is only valid in async function
    at evaluate (rt/40_repl.js:60:36)
    at replLoop (rt/40_repl.js:160:15)
Was this page helpful?
0 / 5 - 0 ratings

Related issues

motss picture motss  路  3Comments

zugende picture zugende  路  3Comments

metakeule picture metakeule  路  3Comments

justjavac picture justjavac  路  3Comments

xueqingxiao picture xueqingxiao  路  3Comments