Give more control over `jsExecutePendingJob` / `_executePendingJob`
Matthiee opened this issue · 1 comments
We are using Zone's to control some aspects of how the eval
code is executed.
If the eval
is executed in CustomZone
, all the JS code that is behind an async/await
will be run in the RootZone
where the QuickJS.dispatch()
is executed. This is incorrect, we would expect all the code in the eval to be run in the CustomZone
.
We can't change this behaviour as there is no way to manually execute pending jobs.
Making the _executePendingJob
public would be sufficient for us.
Closing the QuickJS and running the Dispatch again inside the correct zone is too expensive for us.
@ekibun here is an example test as to why this is needed.
The only difference between the working test and the failing test is the https://api.flutter.dev/flutter/dart-async/runZoned.html being used.
Our application is using custom zones heavily and losing the zone values after the first async/await call is something preventing us from using this library.
In a patched version using #32 we can run the event loop in the custom zone.
Example unit test code:
import 'dart:async';
import 'package:flutter_qjs/flutter_qjs.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
Future<String?> fetch(String url) async {
await Future.delayed(const Duration(milliseconds: 100));
return Zone.current['custom'] as String?;
}
late FlutterQjs qjs;
setUp(() async {
qjs = FlutterQjs();
final setToGlobalFunc =
qjs.evaluate('(key, val) => { this[key] = val; }') as JSInvokable;
setToGlobalFunc.invoke(['fetch', fetch]);
setToGlobalFunc.invoke(['print', print]);
setToGlobalFunc.destroy();
qjs.dispatch();
await qjs.evaluate('''
class MyClass {
async download() {
const result1 = await fetch("http://google.com");
const result2 = await fetch("https://example.com/");
return { a: result1, b: result2 };
}
}
''');
});
test('async fetch (works)', () async {
final result = await qjs.evaluate('(new MyClass()).download()');
print('result here is $result');
expect(result['a'], isNull, reason: 'no zone data available');
expect(result['b'], isNull, reason: 'no zone data available');
});
test('async fetch (broken)', () async {
final result = await runZoned(
() async => await qjs.evaluate('(new MyClass()).download()'),
zoneValues: {
'custom': 'some value',
},
);
print('result here is $result');
expect(result['a'], 'some value', reason: '1st fetch executed in runZoned');
// This contains null, while it should contain the zone value.
// This indicates it has ran outside of the zone.
expect(result['b'], 'some value', reason: '2nd fetch executed in runZoned');
});
}