Handle errors in compute()
by propagating them to the Future. (#24848)
This commit is contained in:
parent
273364e2bc
commit
c5ad1067b7
@ -49,6 +49,7 @@ Future<R> compute<Q, R>(ComputeCallback<Q, R> callback, Q message, { String debu
|
|||||||
final Flow flow = Flow.begin();
|
final Flow flow = Flow.begin();
|
||||||
Timeline.startSync('$debugLabel: start', flow: flow);
|
Timeline.startSync('$debugLabel: start', flow: flow);
|
||||||
final ReceivePort resultPort = ReceivePort();
|
final ReceivePort resultPort = ReceivePort();
|
||||||
|
final ReceivePort errorPort = ReceivePort();
|
||||||
Timeline.finishSync();
|
Timeline.finishSync();
|
||||||
final Isolate isolate = await Isolate.spawn<_IsolateConfiguration<Q, R>>(
|
final Isolate isolate = await Isolate.spawn<_IsolateConfiguration<Q, R>>(
|
||||||
_spawn,
|
_spawn,
|
||||||
@ -61,13 +62,32 @@ Future<R> compute<Q, R>(ComputeCallback<Q, R> callback, Q message, { String debu
|
|||||||
),
|
),
|
||||||
errorsAreFatal: true,
|
errorsAreFatal: true,
|
||||||
onExit: resultPort.sendPort,
|
onExit: resultPort.sendPort,
|
||||||
|
onError: errorPort.sendPort,
|
||||||
);
|
);
|
||||||
final R result = await resultPort.first;
|
final Completer<R> result = Completer<R>();
|
||||||
|
errorPort.listen((dynamic errorData) {
|
||||||
|
assert(errorData is List<dynamic>);
|
||||||
|
assert(errorData.length == 2);
|
||||||
|
final Exception exception = Exception(errorData[0]);
|
||||||
|
final StackTrace stack = StackTrace.fromString(errorData[1]);
|
||||||
|
if (result.isCompleted) {
|
||||||
|
Zone.current.handleUncaughtError(exception, stack);
|
||||||
|
} else {
|
||||||
|
result.completeError(exception, stack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
resultPort.listen((dynamic resultData) {
|
||||||
|
assert(resultData == null || resultData is R);
|
||||||
|
if (!result.isCompleted)
|
||||||
|
result.complete(resultData);
|
||||||
|
});
|
||||||
|
await result.future;
|
||||||
Timeline.startSync('$debugLabel: end', flow: Flow.end(flow.id));
|
Timeline.startSync('$debugLabel: end', flow: Flow.end(flow.id));
|
||||||
resultPort.close();
|
resultPort.close();
|
||||||
|
errorPort.close();
|
||||||
isolate.kill();
|
isolate.kill();
|
||||||
Timeline.finishSync();
|
Timeline.finishSync();
|
||||||
return result;
|
return result.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
@ -92,9 +112,7 @@ void _spawn<Q, R>(_IsolateConfiguration<Q, R> configuration) {
|
|||||||
R result;
|
R result;
|
||||||
Timeline.timeSync(
|
Timeline.timeSync(
|
||||||
'${configuration.debugLabel}',
|
'${configuration.debugLabel}',
|
||||||
() {
|
() { result = configuration.apply(); },
|
||||||
result = configuration.apply();
|
|
||||||
},
|
|
||||||
flow: Flow.step(configuration.flowId),
|
flow: Flow.step(configuration.flowId),
|
||||||
);
|
);
|
||||||
Timeline.timeSync(
|
Timeline.timeSync(
|
||||||
|
22
packages/flutter/test/foundation/isolates_test.dart
Normal file
22
packages/flutter/test/foundation/isolates_test.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
import '../flutter_test_alternative.dart';
|
||||||
|
|
||||||
|
int test1(int value) {
|
||||||
|
return value + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test2(int value) {
|
||||||
|
throw 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('compute()', () async {
|
||||||
|
expect(await compute(test1, 0), 1);
|
||||||
|
expect(compute(test2, 0), throwsA(isInstanceOf<Exception>()));
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user