Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promise of vertx cannot call then twice or more. #587

Open
fantasy0v0 opened this issue May 18, 2022 · 4 comments
Open

Promise of vertx cannot call then twice or more. #587

fantasy0v0 opened this issue May 18, 2022 · 4 comments
Labels
bug Something isn't working

Comments

@fantasy0v0
Copy link
Contributor

fantasy0v0 commented May 18, 2022

$ es4x versions
VM:        OpenJDK 64-Bit Server VM - 17
VM Vendor: null
Vert.x:    4.2.2
ES4X:      0.16.2
graaljs:   21.3.0

code: index.js

import { Promise as VPromise } from "@vertx/core";
let promise = VPromise.promise();
promise.future().then(v => {
  console.log("v:" + v);
  return "v2";
}, (e) => {
  console.log("err");
}).then(v => {
  console.log("v2:" + v);
  return "v3";
}, (e) => {
  console.log("err");
});

error message:

Failed in deploying verticle caused by TypeError: Cannot read property 'then' of null
        at <js> :anonymous(/C:/Users/fan/Desktop/test/demo/index.js:21-31:412-606)
        at <js> _load(node_modules\.lib\es4x-0.16.2.jar!\io\reactiverse\es4x\jvm-npm.js:73:2195-2276)
        at <js> runMain(node_modules\.lib\es4x-0.16.2.jar!\io\reactiverse\es4x\jvm-npm.js:85:2567-2611)
        at org.graalvm.sdk/org.graalvm.polyglot.Value.invokeMember(Value.java:934)
        at io.reactiverse.es4x.impl.JSVerticleFactory$1.lambda$start$0(JSVerticleFactory.java:85)
        at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
        at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
        at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
        at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:833)
@fantasy0v0
Copy link
Contributor Author

fantasy0v0 commented May 18, 2022

then of io.reactiverse.es4x.Thenable Maybe should return new Future.

image

@fantasy0v0
Copy link
Contributor Author

then of io.reactiverse.es4x.Thenable Maybe should return new Future.

image

I tried to modify it, but the problem was not simple.😣https://promisesaplus.com/#the-then-method

@fantasy0v0
Copy link
Contributor Author

fantasy0v0 commented May 23, 2022

I try to implement this with native promises. I testing.

@Override
  public Value then(Value onResolve, Value onReject) {
    try {
      return JavaScript.createPromise(context, (_resolve, _reject) -> {
        Consumer<Object> onResolveNext = value -> {
          if (value instanceof Value _value) {
            if (JavaScript.isPromise(_value)) {
              _value.invokeMember("then", _resolve, _reject);
            } else {
              _resolve.execute(value);
            }
          } else {
            _resolve.execute(value);
          }
        };
        Consumer<Object> onRejectNext = err -> {
          if (err instanceof Value _value) {
            if (JavaScript.isPromise(_value)) {
              _value.invokeMember("then", _resolve, _reject);
            } else {
              _reject.execute(err);
            }
          } else {
            _reject.execute(err);
          }
        };
        future.onComplete(ar -> {
          if (ar.succeeded()) {
            T result = ar.result();
            if (onResolve != null && onResolve.canExecute()) {
              Value value = onResolve.execute(result);
              onResolveNext.accept(value);
            } else {
              _resolve.execute(result);
            }
          } else {
            Throwable cause = ar.cause();
            if (onReject != null && onReject.canExecute()) {
              Value value = onReject.execute(cause);
              onRejectNext.accept(value);
            } else {
              _reject.execute(cause);
            }
          }
        });
      });
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

JavaScript.createPromise implement:

public static Value createPromise(Context context, PromiseExecutor executor) throws IOException {
    Value bindings = context.getBindings("js");
    bindings.putMember("executor", executor);
    try {
      Source source = Source
        .newBuilder("js", "new Promise(executor)", null)
        .build();
      return context.eval(source);
    } finally {
      bindings.removeMember("executor");
    }
  }

@pmlopes
Copy link
Contributor

pmlopes commented May 24, 2022

@fantasy0v0 yes, that is the vert.x behavior, JavaScript has a similar behavior:

let myPromise = new Promise(function(myResolve, myReject) {
  myResolve('OK'); // when successful
  myResolve('OK'); // when successful
});

// "Consuming Code" (Must wait for a fulfilled Promise)
myPromise.then(
  function(value) { console.log(value); },
  function(error) { console.log(error); }
);

With a small difference that calling multiple times will silently ignore the multiple calls. Let's update es4x to be like that, ignore the multiple calls.

@pmlopes pmlopes added the bug Something isn't working label May 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants