WebAssembly and Promise

Elements 11.0.0.2673

Hi,

Is there any way (on WASM side) to await for an async method to complete when the method returns JS Promise? The async/await keywords require native Task. An example where you might need that is the Blob/File.arrayBuffer() method. In JS you can simply write:

var buffer = await blob.arrayBuffer();

but I cannot find a way to do so on the WASM side.

1 Like

Curious. We don’t currently treat js’ promise as an async-able type; but it’s an interesting idea to do so. Maybe with some wrapper for now:

method FutureToAsync(aValue: dynamic): Task<dynamic>;
begin 
  var lCP := new TaskCompletionSource<dynamic>;
  aValue.then(WebAssemblyDelegate(b -> lCP.SetResult(b)), WebAssemblyDelegate(b -> lCP.SetException(new Exception(string(b:ToString()))));
  exit lCP.Task;
end;

Note: untested, written from meory but if you are oke with this approach I can work it out a bit if needed.

You can then do

var buffer := await FutureToAsync(blob.arrayBuffer)
2 Likes

Logged as bugs://E25397.

Thank you Carlo. However, the wrapper you suggested doesn’t seem to work - I get

Null Reference Exception for expression: self.fTask

inside the method. If you could work it out then we would be able to proceed instead of waiting for the bug to be resolved.

Try this:

class method FutureToAsync(aValue: dynamic): Task<dynamic>;
    begin
      var lCP := new TaskCompletionSource<dynamic>;
      result := lCP.Task;
      var lCall, lExCall: WebAssemblyDelegate;
      lCall := b -> begin
        lCP.SetResult(b);
        SimpleGC.ForceRelease(IntPtr(InternalCalls.Cast(lCP)));
        SimpleGC.ForceRelease(IntPtr(InternalCalls.Cast(lCall)));
        SimpleGC.ForceRelease(IntPtr(InternalCalls.Cast(lExCall)));
      end;
      lExCall := b -> begin
        lCP.SetException(new Exception(String(b:ToString())));
        SimpleGC.ForceRelease(IntPtr(InternalCalls.Cast(lCP)));
        SimpleGC.ForceRelease(IntPtr(InternalCalls.Cast(lCall)));
        SimpleGC.ForceRelease(IntPtr(InternalCalls.Cast(lExCall)));
      end;

      SimpleGC.ForceAddRef(IntPtr(InternalCalls.Cast(lCP)));
      SimpleGC.ForceAddRef(IntPtr(InternalCalls.Cast(lCall)));
      SimpleGC.ForceAddRef(IntPtr(InternalCalls.Cast(lExCall)));
      aValue.then(lCall, lExCall);
    end;

So what will work in next fridays build:


    method DoIt;
    begin
      writeLn(await WebAssembly.Global.AsyncCall()); // prints p2
    end;

With this js:


      function AsyncCall() {
        return new Promise((res) => setTimeout(() => res("p2"), 500));
      }
1 Like

Great! Just so you know, the wrapper doesn’t seem to work, I did what you said and I keep getting null as the result. But never mind, I’ll wait for the friday’s build.