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

Give more control over jsExecutePendingJob / _executePendingJob #31

Open
Matthiee opened this issue Oct 18, 2022 · 1 comment · May be fixed by #32
Open

Give more control over jsExecutePendingJob / _executePendingJob #31

Matthiee opened this issue Oct 18, 2022 · 1 comment · May be fixed by #32

Comments

@Matthiee
Copy link

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.

Matthiee added a commit to Matthiee/flutter_qjs that referenced this issue Oct 18, 2022
@Matthiee Matthiee linked a pull request Oct 18, 2022 that will close this issue
@Matthiee
Copy link
Author

Matthiee commented Nov 9, 2023

@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');
  });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant