Skip to content

Commit cf43c66

Browse files
committed
feat: update README.md
1 parent 925bcf8 commit cf43c66

File tree

2 files changed

+191
-166
lines changed

2 files changed

+191
-166
lines changed

README.md

Lines changed: 8 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -34,147 +34,17 @@ try (JSRuntime runtime = quickJS.createJSRuntime()) {
3434
}
3535
```
3636

37-
### Call Java Methods in Javascript Scripts
38-
39-
Non-static methods and static methods are supported. Wrap a Java method as a JSFunction, then add the JSFunction to the JSContext. Call it like a normal Javascript function.
40-
41-
```Java
42-
QuickJS quickJS = new QuickJS.Builder().build();
43-
try (JSRuntime runtime = quickJS.createJSRuntime()) {
44-
try (JSContext context = runtime.createJSContext()) {
45-
// Non-static method
46-
Integer integer = 0;
47-
JSFunction zeroCompareTo = context.createJSFunction(integer, Method.create(Integer.class, Integer.class.getMethod("compareTo", Integer.class)));
48-
// Add the function to the global object
49-
context.getGlobalObject().setProperty("zeroCompareTo", zeroCompareTo);
50-
assertEquals(-1, (int) context.evaluate("zeroCompareTo(1)", "test.js", int.class));
51-
assertEquals(1, (int) context.evaluate("zeroCompareTo(-1)", "test.js", int.class));
52-
53-
// Static method
54-
JSFunction javaAbs = context.createJSFunctionS(Math.class, Method.create(Math.class, Math.class.getMethod("abs", int.class)));
55-
// Add the function to the global object
56-
context.getGlobalObject().setProperty("javaAbs", javaAbs);
57-
assertEquals(1, (int) context.evaluate("javaAbs(1)", "test.js", int.class));
58-
assertEquals(1, (int) context.evaluate("javaAbs(-1)", "test.js", int.class));
59-
}
60-
}
61-
```
62-
63-
Or create a JSFunction with a callback.
64-
65-
```Java
66-
QuickJS quickJS = new QuickJS.Builder().build();
67-
try (JSRuntime runtime = quickJS.createJSRuntime()) {
68-
try (JSContext context = runtime.createJSContext()) {
69-
// Create a JSFunction with a callback
70-
JSValue plusFunction = context.createJSFunction((context, args) -> {
71-
int a = args[0].cast(JSNumber.class).getInt();
72-
int b = args[1].cast(JSNumber.class).getInt();
73-
int sum = a + b;
74-
return context.createJSNumber(sum);
75-
});
76-
77-
context.getGlobalObject().setProperty("plus", plusFunction);
78-
int result = context.evaluate("plus(1, 2)", "test.js", Integer.class);
79-
assertThat(result).isEqualTo(3);
80-
}
81-
}
82-
```
83-
84-
### Call Javascript Methods in Java codes
85-
86-
Just **evaluate** it. Or call `JSFunction.invoke()`.
87-
88-
### Promise
89-
90-
Use `JSContext.executePendingJob()` to execute pending job of promises. You may call `JSContext.executePendingJob()` several times until it returns `false`.
91-
92-
```Java
93-
QuickJS quickJS = new QuickJS.Builder().build();
94-
try (JSRuntime runtime = quickJS.createJSRuntime()) {
95-
try (JSContext context = runtime.createJSContext()) {
96-
context.evaluate("a = 1;Promise.resolve().then(() => { a = 2 })", "test.js");
97-
assertEquals(1, context.getGlobalObject().getProperty("a").cast(JSNumber.class).getInt());
98-
// Execute the pending job
99-
assertTrue(context.executePendingJob());
100-
assertEquals(2, context.getGlobalObject().getProperty("a").cast(JSNumber.class).getInt());
101-
// No pending job
102-
assertFalse(context.executePendingJob());
103-
}
104-
}
105-
```
106-
107-
### Conversion between Java Values and Javascript Values
108-
109-
Java values are converted to Javascript values when calling Java methods in Javascript scripts. Javascript values are converted to a Java values when receiving return values from evaluated Javascript scripts. QuickJS Android supports primitive types, string, array.
110-
111-
```Java
112-
QuickJS quickJS = new QuickJS.Builder().build();
113-
try (JSRuntime runtime = quickJS.createJSRuntime()) {
114-
try (JSContext context = runtime.createJSContext()) {
115-
String[] result = context.evaluate("['hello', 'world']", "test.js", String[].class);
116-
assertArrayEquals(new String[] { "hello", "world" }, result);
117-
}
118-
}
119-
```
120-
121-
Java Interfaces are also supported.
122-
123-
```Java
124-
interface Calculator {
125-
double plus(double a, double b);
126-
double minus(double a, double b);
127-
double multiplies(double a, double b);
128-
double divides(double a, double b);
129-
void noop();
130-
}
131-
132-
QuickJS quickJS = new QuickJS.Builder().build();
133-
try (JSRuntime runtime = quickJS.createJSRuntime()) {
134-
try (JSContext context = runtime.createJSContext()) {
135-
Calculator calculator = context.evaluate("" +
136-
"a = {\n" +
137-
" plus: function(a, b) { return a + b },\n" +
138-
" minus: function(a, b) { return a - b },\n" +
139-
" multiplies: function(a, b) { return a * b },\n" +
140-
" divides: function(a, b) { return a / b },\n" +
141-
" noop: function() { }\n" +
142-
"}", "test.js", Calculator.class);
143-
}
144-
}
145-
```
146-
147-
Use `TypeAdapter` to support any type you like.
148-
149-
```Java
150-
private static class AtomicIntegerTypeAdapter extends TypeAdapter<AtomicInteger> {
151-
@Override
152-
public JSValue toJSValue(Depot depot, Context context, AtomicInteger value) {
153-
return context.createJSNumber(value.get());
154-
}
155-
156-
@Override
157-
public AtomicInteger fromJSValue(Depot depot, Context context, JSValue value) {
158-
return new AtomicInteger(value.cast(JSNumber.class).getInt());
159-
}
160-
}
161-
162-
QuickJS quickJS = new QuickJS.Builder().registerTypeAdapter(AtomicInteger.class, new AtomicIntegerTypeAdapter()).build();
163-
try (JSRuntime runtime = quickJS.createJSRuntime()) {
164-
try (JSContext context = runtime.createJSContext()) {
165-
AtomicInteger atomicInteger = context.evaluate("1", "test.js", AtomicInteger.class);
166-
assertEquals(1, atomicInteger.get());
167-
}
168-
}
169-
```
37+
See [Usages](./Usages.md) for advanced usages.
17038

17139
## Benchmark
17240

173-
| Engine | v8 | QuickJS (Bytecode Mode) |
174-
| :-: | :-: | :-: |
175-
| init | 30ms | 14ms |
176-
| eval | 29ms | 47ms |
177-
| total | 59ms | 61ms |
41+
This is a non-serious benchmark. The purpose is to compare the performance of QuickJS and V8 on Android.
42+
43+
| Engine | v8 | QuickJS (Bytecode Mode) |
44+
| :----: | :--: | :---------------------: |
45+
| init | 30ms | 14ms |
46+
| eval | 29ms | 47ms |
47+
| total | 59ms | 61ms |
17848

17949
- Device: Huawei P30 Pro (Kirin 980), Android 10.
18050
- Test JavaScript File: `asset:/sonic.js` (189 KB).
@@ -184,34 +54,6 @@ try (JSRuntime runtime = quickJS.createJSRuntime()) {
18454
1. Even when operating in bytecode mode, QuickJS's evaluation time is notably higher than V8's, and this disparity intensifies as the JavaScript file size increases.
18555
2. QuickJS's initialization time is slightly lower than V8's, and this advantage is constant despite of file sizes.
18656

187-
## Concept
188-
189-
QuickJS Android uses the similar APIs to QuickJS.
190-
191-
### JSRuntime
192-
193-
> JSRuntime represents a Javascript runtime corresponding to an object heap. Several runtimes can exist at the same time but they cannot exchange objects. Inside a given runtime, no multi-threading is supported.
194-
>
195-
> -- QuickJS Document
196-
197-
### JSContext
198-
199-
> JSContext represents a Javascript context (or Realm). Each JSContext has its own global objects and system objects. There can be several JSContexts per JSRuntime and they can share objects, similar to frames of the same origin sharing Javascript objects in a web browser.
200-
>
201-
> -- QuickJS Document
202-
203-
### JSValue
204-
205-
> JSValue represents a Javascript value which can be a primitive type or an object.
206-
>
207-
> -- QuickJS Document
208-
209-
Available subclasses of `JSValue` are `JSNull`, `JSUndefined`, `JSBoolean`, `JSNumber`, `JSString`, `JSObject`, `JSArray`, `JSFunction`, `JSSymbol`.
210-
211-
## Test
212-
213-
The original tests and benchmarks of QuickJS are in [android-test](android-test). It's a console-like app running all tests and benchmarks at startup, like `make test`.
214-
21557
## Acknowledgement
21658

21759
1. [bellard/quickjs](https://github.com/bellard/quickjs) QuickJS official repository.

Usages.md

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# Usages
2+
3+
## Concept
4+
5+
QuickJS Android uses the similar APIs to QuickJS.
6+
7+
### JSRuntime
8+
9+
> JSRuntime represents a Javascript runtime corresponding to an object heap. Several runtimes can exist at the same time but they cannot exchange objects. Inside a given runtime, no multi-threading is supported.
10+
>
11+
> -- QuickJS Document
12+
13+
### JSContext
14+
15+
> JSContext represents a Javascript context (or Realm). Each JSContext has its own global objects and system objects. There can be several JSContexts per JSRuntime and they can share objects, similar to frames of the same origin sharing Javascript objects in a web browser.
16+
>
17+
> -- QuickJS Document
18+
19+
### JSValue
20+
21+
> JSValue represents a Javascript value which can be a primitive type or an object.
22+
>
23+
> -- QuickJS Document
24+
25+
Available subclasses of `JSValue` are `JSNull`, `JSUndefined`, `JSBoolean`, `JSNumber`, `JSString`, `JSObject`, `JSArray`, `JSFunction`, `JSSymbol`.
26+
27+
## Examples
28+
29+
### Evaluate Javascript Scripts
30+
31+
```Java
32+
QuickJS quickJS = new QuickJS.Builder().build();
33+
try (JSRuntime runtime = quickJS.createJSRuntime()) {
34+
try (JSContext context = runtime.createJSContext()) {
35+
String script1 = "" +
36+
"function fibonacci(n) {" +
37+
" if (n == 0 || n == 1) return n;" +
38+
" return fibonacci(n - 1) + fibonacci(n - 2);" +
39+
"}";
40+
// Evaluate a script without return value
41+
context.evaluate(script1, "fibonacci.js");
42+
43+
String script2 = "fibonacci(10);";
44+
// Evaluate a script with return value
45+
int result = context.evaluate(script2, "fibonacci.js", int.class);
46+
assertEquals(55, result);
47+
}
48+
}
49+
```
50+
51+
### Call Java Methods in Javascript Scripts
52+
53+
Non-static methods and static methods are supported. Wrap a Java method as a JSFunction, then add the JSFunction to the JSContext. Call it like a normal Javascript function.
54+
55+
```Java
56+
QuickJS quickJS = new QuickJS.Builder().build();
57+
try (JSRuntime runtime = quickJS.createJSRuntime()) {
58+
try (JSContext context = runtime.createJSContext()) {
59+
// Non-static method
60+
Integer integer = 0;
61+
JSFunction zeroCompareTo = context.createJSFunction(integer, Method.create(Integer.class, Integer.class.getMethod("compareTo", Integer.class)));
62+
// Add the function to the global object
63+
context.getGlobalObject().setProperty("zeroCompareTo", zeroCompareTo);
64+
assertEquals(-1, (int) context.evaluate("zeroCompareTo(1)", "test.js", int.class));
65+
assertEquals(1, (int) context.evaluate("zeroCompareTo(-1)", "test.js", int.class));
66+
67+
// Static method
68+
JSFunction javaAbs = context.createJSFunctionS(Math.class, Method.create(Math.class, Math.class.getMethod("abs", int.class)));
69+
// Add the function to the global object
70+
context.getGlobalObject().setProperty("javaAbs", javaAbs);
71+
assertEquals(1, (int) context.evaluate("javaAbs(1)", "test.js", int.class));
72+
assertEquals(1, (int) context.evaluate("javaAbs(-1)", "test.js", int.class));
73+
}
74+
}
75+
```
76+
77+
Or create a JSFunction with a callback.
78+
79+
```Java
80+
QuickJS quickJS = new QuickJS.Builder().build();
81+
try (JSRuntime runtime = quickJS.createJSRuntime()) {
82+
try (JSContext context = runtime.createJSContext()) {
83+
// Create a JSFunction with a callback
84+
JSValue plusFunction = context.createJSFunction((context, args) -> {
85+
int a = args[0].cast(JSNumber.class).getInt();
86+
int b = args[1].cast(JSNumber.class).getInt();
87+
int sum = a + b;
88+
return context.createJSNumber(sum);
89+
});
90+
91+
context.getGlobalObject().setProperty("plus", plusFunction);
92+
int result = context.evaluate("plus(1, 2)", "test.js", Integer.class);
93+
assertThat(result).isEqualTo(3);
94+
}
95+
}
96+
```
97+
98+
### Call Javascript Methods in Java codes
99+
100+
Just **evaluate** it. Or call `JSFunction.invoke()`.
101+
102+
### Promise
103+
104+
Use `JSContext.executePendingJob()` to execute pending job of promises. You may call `JSContext.executePendingJob()` several times until it returns `false`.
105+
106+
```Java
107+
QuickJS quickJS = new QuickJS.Builder().build();
108+
try (JSRuntime runtime = quickJS.createJSRuntime()) {
109+
try (JSContext context = runtime.createJSContext()) {
110+
context.evaluate("a = 1;Promise.resolve().then(() => { a = 2 })", "test.js");
111+
assertEquals(1, context.getGlobalObject().getProperty("a").cast(JSNumber.class).getInt());
112+
// Execute the pending job
113+
assertTrue(context.executePendingJob());
114+
assertEquals(2, context.getGlobalObject().getProperty("a").cast(JSNumber.class).getInt());
115+
// No pending job
116+
assertFalse(context.executePendingJob());
117+
}
118+
}
119+
```
120+
121+
### Conversion between Java Values and Javascript Values
122+
123+
Java values are converted to Javascript values when calling Java methods in Javascript scripts. Javascript values are converted to a Java values when receiving return values from evaluated Javascript scripts. QuickJS Android supports primitive types, string, array.
124+
125+
```Java
126+
QuickJS quickJS = new QuickJS.Builder().build();
127+
try (JSRuntime runtime = quickJS.createJSRuntime()) {
128+
try (JSContext context = runtime.createJSContext()) {
129+
String[] result = context.evaluate("['hello', 'world']", "test.js", String[].class);
130+
assertArrayEquals(new String[] { "hello", "world" }, result);
131+
}
132+
}
133+
```
134+
135+
Java Interfaces are also supported.
136+
137+
```Java
138+
interface Calculator {
139+
double plus(double a, double b);
140+
double minus(double a, double b);
141+
double multiplies(double a, double b);
142+
double divides(double a, double b);
143+
void noop();
144+
}
145+
146+
QuickJS quickJS = new QuickJS.Builder().build();
147+
try (JSRuntime runtime = quickJS.createJSRuntime()) {
148+
try (JSContext context = runtime.createJSContext()) {
149+
Calculator calculator = context.evaluate("" +
150+
"a = {\n" +
151+
" plus: function(a, b) { return a + b },\n" +
152+
" minus: function(a, b) { return a - b },\n" +
153+
" multiplies: function(a, b) { return a * b },\n" +
154+
" divides: function(a, b) { return a / b },\n" +
155+
" noop: function() { }\n" +
156+
"}", "test.js", Calculator.class);
157+
}
158+
}
159+
```
160+
161+
Use `TypeAdapter` to support any type you like.
162+
163+
```Java
164+
private static class AtomicIntegerTypeAdapter extends TypeAdapter<AtomicInteger> {
165+
@Override
166+
public JSValue toJSValue(Depot depot, Context context, AtomicInteger value) {
167+
return context.createJSNumber(value.get());
168+
}
169+
170+
@Override
171+
public AtomicInteger fromJSValue(Depot depot, Context context, JSValue value) {
172+
return new AtomicInteger(value.cast(JSNumber.class).getInt());
173+
}
174+
}
175+
176+
QuickJS quickJS = new QuickJS.Builder().registerTypeAdapter(AtomicInteger.class, new AtomicIntegerTypeAdapter()).build();
177+
try (JSRuntime runtime = quickJS.createJSRuntime()) {
178+
try (JSContext context = runtime.createJSContext()) {
179+
AtomicInteger atomicInteger = context.evaluate("1", "test.js", AtomicInteger.class);
180+
assertEquals(1, atomicInteger.get());
181+
}
182+
}
183+
```

0 commit comments

Comments
 (0)