Jint: async/await and callback support

Created on 18 Jun 2018  路  10Comments  路  Source: sebastienros/jint

I was surprised to find no issues nor pull requests to support C#/JS async/await and Task support.

In a perfect world, I could make that transparent and "halt" the calling method (like #192), or use a callback mechanism (which would make scripts much more complex however).

I'd prefer to avoid using return task.Result and friends, so that I don't get into a deadlock eventually.

Before investigating this further, did anyone actually attempt any async/await support in Jint? @sebastienros is this something you'd be interested in supporting, e.g. through the native ECMA-262 async/await (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)? Any failed or partial attempt?

To avoid any confusion, given this C# code:

public async Task<string> loadSomething(string path) {
  return await File.ReadAllTextAsync(path);
}

I'd consider any of these JavaScript equivalents to be correct (in order of preference):

// Pausing (easiest for script writers):
var x = loadSomething('test.txt');
// Async Function (concise)
var x = await loadSomething('test.txt');
// Promises (well known)
var x;
loadSomething('test.txt').then(function(result) { x = result });;
// Callbacks (worst case)
var x;
loadSomething('test.txt', function(result) { x = result });;

Any ideas or feedback on that is welcome; I'd like to avoid spending any time on this if it would not be merged, or if the effort is too large for what I can afford.

es6

Most helpful comment

Promise support has been implemented, but no support for async/await keywords yet.

All 10 comments

Can you not convert simple callback into promise using following?

```c#
public class AsyncService {
public void LoadAsync(JValue input, JValue then, JValue failed) {
Task.Run(async () => {
try {
var result = await ..... async processing in C#
then.Invoke( null, result );
} catch(Exception ex) {
failed.Invoke(null, ex.ToString());
}
});
}
}

```TypeScript

             loadAsync( input ) : Promise<any> {
                  return new Promise((resolve,reject) => {
                           asyncService.loadAsync( input, resolve, reject);
                  });
             }


     // now you can use loadAsync method with async await

@ackava thanks for sharing your ideas. It looks like you are using TypeScript, which would explain why using the Promise constructor, the => syntax and eventually using await would work for you :) Using a transpiler is an idea worth investigating though.

I realize that supporting async/await would pretty much be supporting ES2017, which has it's own open issue: https://github.com/sebastienros/jint/issues/343 - this would probably (I can only guess) solve my issue, depending on how @sebastienros decided to implement "await" for C#-backed functions. For now, the Promise constructor looks like it's not implemented in the 3.0 branch, so I guess we'll have to wait and see. If I had more time, I'd try contribute this back in Jint, but I don't think I'll be able to take the lead on this for some time.

If someone else wonders how to do transpiling in Jint: https://github.com/sebastienros/jint/issues/274 (did not try it yet)

Hi everyone, I echo @christianrondeau in the desire for async/await support.

While promises would work, it would be even simpler if the Engine could just "await" a function delegate passed to "SetValue" - if that delegate wrapped an asynchronous method.

Suppose we had the following C# code:

Engine engine = new Engine(cfg => cfg.AllowClr());
Func<string, Task<string>> thisFunc = DoOperation;
engine.SetValue("DoOperation", thisFunc);

//C# method of DoOperation
public async Task<string> DoOperation(string input)
{
   //assume that SomeAsynchronousOperation returns a string...

   return await SomeAsynchronousOperation();
}

The ideal scenario would then be for an "ExecuteAsync" method on the engine like:

engine.ExecuteAsync("DoOperation('my_input');");

...where internally the engine would "await" the function delegate at the time of invocation.

@sebastienros , is this at all possible? If not, are there any other workarounds you might suggest?

Jint is a phenomenal piece of software though in my particular case, I'm dealing with heavy network I/O. As such, async/await support is critical.

Has anybody had any progress on this issue that's worth sharing? I'm in a situation where I need to call some async methods.

Hello,
I've maybe a solution for you, it doesn't use await syntax but you can use then(...) :

C# function to call from JS :

public static Promise<bool> alert(string msg)
        {
            return new Promise<bool>(Task.Run<Task<bool>>(new Func<Task<bool>>(async() => { 

                bool isFinished = false;
                Device.BeginInvokeOnMainThread(async () =>
                {
                    await App.Current.MainPage.DisplayAlert("Message", msg, "Ok");
                    isFinished = true;
                });
                while (!isFinished) await Task.Delay(10);
                return true;
            })));
        }

C# Class "Promise" :

public class Promise<T>
    {
        Task<T> tache;
        public Promise(Task<T> tache)
        {
            this.tache = tache;
        }
        public Promise(Task<Task<T>> tache)
        {
            this.tache = tache.Result;

        }
        public void then(Action<T> onfinish)
        {
            this.tache.ContinueWith(rep =>
            {
                onfinish.Invoke(rep.Result);
            });
        }

    }

Javascript code :

var repAlert=alert("valeur interne = "+valeur);
    repAlert.then(function(rep){
        console.log("journal ok rep="+rep); // return Boolean value (true)
    });
    console.log("journal ok repAlert="+repAlert); // Return Promise object

The catch function is not implemented but you'll can do with this example...

This code is a part of a Xamarin project

Bumping this one for a question: Since Jint is an interpreter, are there any reasons that C# methods cannot be async/return Task, but made look synchronously to the user-script?

I have a case with very many small simple scripts, that should call async methods. I'd like to avoid the complexity of introducing await/Promise objects to the user scripts, because none of the scripts have parallelism requiring actual async code.

You want to be able to do await, then? But do that automatically.
One of the purposes of the Task API is to let you run things in the background, after all.

You want to be able to do await, then? But do that automatically.
One of the purposes of the Task API is to let you run things in the background, after all.

Yes, but the user scripts in my case don't really need it. Still, the host process needs it to avoid blocking the thread.

That might actually be a good idea to support, so the API isn't async based to the script, but is async for the usage.

Promise support has been implemented, but no support for async/await keywords yet.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mikeswanson picture mikeswanson  路  3Comments

lahma picture lahma  路  15Comments

tricuongle picture tricuongle  路  5Comments

hnafar picture hnafar  路  3Comments

appel1 picture appel1  路  25Comments