flutterjavascriptcore

How to use JSObjectMakeDeferredPromise of JavascriptCore


I use flutter_jscore lib, I want to make a async call from javascript to flutter. I use JSObjectMakeDeferredPromise, after async tasks from flutter side, I called resolve function, but the code resolve or reject from javascript maybe not called, I didnt seen any document about JSObjectMakeDeferredPromise, please correct my code, maybe I didnt understand the function, or my code have bugs.

This is my code:

// Init JsContext and register getUser function

var _jsContext = JSContext.createInGroup();
var jsGetUserFunction = JSObject.makeFunctionWithCallback(
        _jsContext, 'getUser', Pointer.fromFunction(getUser));

_jsContext.globalObject.setProperty('getUser', jsGetUserFunction.toValue(),
        JSPropertyAttributes.kJSPropertyAttributeNone);

// This is code of getUser flutter

Pointer getUser(
      Pointer ctx,
      Pointer function,
      Pointer thisObject,
      int argumentCount,
      Pointer<Pointer> arguments,
      Pointer<Pointer> exception) {
   
   var resolve = JSObject.makeFunction(
          _jsContext, 'resolve', JSStringPointer.array(['value']), '', '');

      var reject = JSObject.makeFunction(
          _jsContext, 'reject', JSStringPointer.array(['value']), '', '');

      final promise = JSObject.makeDeferredPromise(_jsContext,
          JSObjectPointer(resolve.pointer), JSObjectPointer(reject.pointer));

      print('created promise');

      fetchUser().then((value) {
        print('fetch done!');

        var pointerValue =
            JSValuePointer(JSValue.makeString(_jsContext, value).pointer);

      
        resolve.callAsFunction(resolve, pointerValue);

        print('resolve')

        return nullptr;
      });

      return promise.pointer;
  }

Future<String> fetchUser() async {
    await new Future.delayed(const Duration(seconds: 3));
    return "user info";
  }

My javascript code

Test1

var promiseFunc = getUser();
console.log(promiseFunc);

promiseFunc.then(function(value) {
   console.log(value);
});

Output:

[object Promise]

Expected:

[object Promise]
'user info'

Test2:

 async function helloJs() {
       await getUser();
       console.log('after wait');
 }
 helloJs();

Result:

calling getUser

Expected:

calling getUser
after wait

Maybe await getUser will wait forever, it's waiting for the resolve function call from the flutter side, my code already called resolve function, but I dont know why .then(..) {...} not run in javascript side.


Solution

  • You need to override "then" function of the promise object, do something like this:

        JSObjectPointer resolve = JSObjectPointer(nullptr);
    JSObjectPointer reject = JSObjectPointer(nullptr);
    JSObject promise = JSObject.makeDeferredPromise(context, resolve, reject);
    var thenFunc = JSObject.makeFunction(context, "then", JSStringPointer.array(['resolve']), "this.resolve=resolve", "");
    promise.setProperty("then", thenFunc.toValue(), JSPropertyAttributes.kJSPropertyAttributeNone);
    http.get(Uri.parse(url)).then((response) {
      if (response.statusCode == 200) {
        var resolveFunc = promise.getProperty("resolve");
        print(resolveFunc.string);
        return (JSObject(context, resolveFunc.toObject()!.pointer))
            .callAsFunction(JSObject(context, thisObject), JSValuePointer(JSValue.makeString(context, response.body).pointer));
      }
    });