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
feat: native Promise APIs #10554
feat: native Promise APIs #10554
Conversation
Thanks for the contribution @drauggres ! |
|
@drauggres I would absolutely love to get this in so we can offer Promise based APIs for any async methods. However, I'm wary of doing so without some tests in our suite for it. We can't test permission requests in our unit test suite, so the changes here aren't something we can test. But maybe if you can modify our WebViewProxy.java to support Promises in place of a callback function? Or does that not work because it's return type is |
Another general idea: This clearly coincides with usage of KrollFunction in the APIs. Maybe there's some way to unify the idea of an optional callback function which if not specified becomes a Promise? I dunno, just throwing ideas out there. We clearly have some funky legacy APIs that can be run sync or async and may return values in sync mode so the idea of enforcing a void return type for this to happen might not cover all cases. |
@sgtcoolguy I agree, similar to the behaviour I have in I would prefer we have this backwards compatibility. |
Instead of implementing promises natively per platform, we can keep the native APIs as-is (still using Something like the below... var oldRequestMethod = Ti.Filesystem.requestStoragePermissions;
Ti.Filesystem.requestStoragePermissions = function(callback) {
// Don't use a promise if a callback was given. (Legacy behavior.)
if (callback) {
oldRequestMethod(callback);
return;
}
// Callback not provided. Use promises solution instead.
return new Promise(function(resolve, reject) {
oldRequestMethod(function(result) {
if (result.success) {
resolve(result);
} else {
reject(result);
}
});
});
}; The only issues that are blocking us from doing the above are:
|
@jquick-axway This is not about migrating permissions-requests-API to promises. What I want is to have ability to create native modules with modern API. Of course we can wrap any callbacks into promises, there are already projects doing this.
I would prefer to not closely integrate KrollFunction and KrollPromise. It works fine like this. Changes in PermReqAPI allow to use it both ways without breaking anything (sample is in the PR description). Somedays some new APIs will be created and there are no reason for them to be callback-based.
Yeah, there are always some legacy, but, once again, this PR is not about changing any current APIs. The second commit here is mostly for example.
OK, I'll modify this methods and add tests soon. I was thinking about creating a module for testing interface generation itself with method/tests like:
|
Done. |
We're planning to do 8.0.0 RC this week, so just looking at our timeline this will definitely need to get bumped to 8.1.0 - updated the milestone for now. |
|
910703b
to
214b337
Compare
android/runtime/v8/src/java/org/appcelerator/kroll/runtime/v8/V8Promise.java
Outdated
Show resolved
Hide resolved
...id/kroll-apt/src/main/resources/org/appcelerator/kroll/annotations/generator/ProxyBinding.fm
Outdated
Show resolved
Hide resolved
948da56
to
f8ad156
Compare
@garymathews This PR was really intended to enable native promises and modified some APIs as a proof of concept. But yeah we should look to enable returning promises for all async APIs we can once this is in. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CR: PASS
android/titanium/src/java/org/appcelerator/titanium/TiBaseActivity.java
Outdated
Show resolved
Hide resolved
@sgtcoolguy, regarding our direct Java 8 supports static methods within an interface. So, it could be set up to be used like this... KrollPromise promise = KrollPromise.create((promise) -> {
if (successful) {
promise.resolve("I did it.");
} else {
promise.reject("I failed.");
}
});
return promise; And ideally you should be able to use it without a callback. This may make it easier to integrate into other APIs. KrollPromise promise = KrollPromise.create();
if (successful) {
promise.resolve("I did it.");
} else {
promise.reject("I failed.");
}
return promise; We could implement public interface KrollPromise {
interface OnExecuteCallback {
void onExecute(KrollPromise promise);
}
void resolve(Object value);
void reject(Object value);
static KrollPromise create() {
return create(null);
}
static KrollPromise create(OnExecuteCallback callback) {
KrollPromise promise = KrollRuntime.getInstance().createPromise();
if (promise == null) {
promise = new MockPromise();
}
if (callback != null) {
TiMessenger.postOnRuntime(() -> {
callback.onExecute(promise);
});
}
return promise;
}
private static class MockPromise implements KrollPromise {
@Override
public void resolve(Object value) {}
@Override
public void reject(Object value) {}
}
}
public abstract class KrollRuntime {
public abstract KrollPromise createPromise();
}
public class V8Runtime extends KrollRuntime {
@Override
public KrollPromise createPromise() {
if (KrollRuntime.isDisposed()) {
return null;
}
return new V8Promsie();
}
} I'm not trying to cause trouble. Just tossing in some ideas here. |
@jquick-axway re: the callback - yes, it's definitely needed, otherwise there's no way to ensure the promise "body" is going to be async. If we simply create a promise and keep on executing, we're running the code sync but pretending it's async - the promise will already have rejected/resolved by the time the method returns it. I do see your point that we have typically hid the JS-engine specific subclass vs the |
Fixes TIMOB-24549
Fixes TIMOB-24549
…ext.currentContext is nil
f3ef6f8
to
35bc9c4
Compare
For reference, I've opened https://jira.appcelerator.org/browse/TIMOB-28279 to track enabling more of our APIs to return Promises. |
JIRA: https://jira.appcelerator.org/browse/TIMOB-24549
I suggest to reopen TIMOB-24549.
This PR introduces an interface for creating asynchronous methods (for native Android modules) that return ES6 Promise.
Sample application: