mirror of https://github.com/grpc/grpc-dart.git
Use AbortController and AbortSignal to properly cancel fetches.
This commit is contained in:
parent
5a8818b527
commit
3b409ad3cb
|
@ -33,6 +33,19 @@ import 'web_streams.dart';
|
||||||
|
|
||||||
const _contentTypeKey = 'Content-Type';
|
const _contentTypeKey = 'Content-Type';
|
||||||
|
|
||||||
|
@JS()
|
||||||
|
class AbortSignal {
|
||||||
|
external factory AbortSignal();
|
||||||
|
external bool get aborted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JS()
|
||||||
|
class AbortController {
|
||||||
|
external factory AbortController();
|
||||||
|
external void abort([dynamic reason]);
|
||||||
|
external AbortSignal get signal;
|
||||||
|
}
|
||||||
|
|
||||||
@anonymous
|
@anonymous
|
||||||
// ignore: missing_js_lib_annotation
|
// ignore: missing_js_lib_annotation
|
||||||
@JS()
|
@JS()
|
||||||
|
@ -41,6 +54,7 @@ class RequestInit {
|
||||||
{required String method,
|
{required String method,
|
||||||
Object? headers,
|
Object? headers,
|
||||||
List<int>? body,
|
List<int>? body,
|
||||||
|
AbortSignal? signal,
|
||||||
required String referrerPolicy,
|
required String referrerPolicy,
|
||||||
required String mode,
|
required String mode,
|
||||||
required String credentials,
|
required String credentials,
|
||||||
|
@ -58,6 +72,9 @@ class RequestInit {
|
||||||
external Uint8List? get body;
|
external Uint8List? get body;
|
||||||
external set body(Uint8List? newValue);
|
external set body(Uint8List? newValue);
|
||||||
|
|
||||||
|
external AbortSignal? get signal;
|
||||||
|
external set signal(AbortSignal? newValue);
|
||||||
|
|
||||||
external String get referrerPolicy;
|
external String get referrerPolicy;
|
||||||
external set referrerPolicy(String newValue);
|
external set referrerPolicy(String newValue);
|
||||||
|
|
||||||
|
@ -106,7 +123,7 @@ class FetchHttpRequest {
|
||||||
Stream<int> get onError => onErrorController.stream;
|
Stream<int> get onError => onErrorController.stream;
|
||||||
|
|
||||||
// Response information
|
// Response information
|
||||||
CancelableOperation<dynamic>? _cancelableFetch;
|
AbortController? _abortController;
|
||||||
CancelableOperation<dynamic>? _cancelableSend;
|
CancelableOperation<dynamic>? _cancelableSend;
|
||||||
dynamic _response;
|
dynamic _response;
|
||||||
Uint8List? _lastResponse;
|
Uint8List? _lastResponse;
|
||||||
|
@ -155,6 +172,7 @@ class FetchHttpRequest {
|
||||||
final wgs = WorkerGlobalScope.instance;
|
final wgs = WorkerGlobalScope.instance;
|
||||||
_setReadyState(HttpRequest.LOADING);
|
_setReadyState(HttpRequest.LOADING);
|
||||||
|
|
||||||
|
_abortController = AbortController();
|
||||||
final init = RequestInit(
|
final init = RequestInit(
|
||||||
cache: cache,
|
cache: cache,
|
||||||
credentials: credentials,
|
credentials: credentials,
|
||||||
|
@ -164,17 +182,19 @@ class FetchHttpRequest {
|
||||||
mode: mode,
|
mode: mode,
|
||||||
redirect: redirect,
|
redirect: redirect,
|
||||||
referrerPolicy: referrerPolicy,
|
referrerPolicy: referrerPolicy,
|
||||||
|
signal: _abortController?.signal,
|
||||||
body: data,
|
body: data,
|
||||||
headers: js_util.jsify(headers));
|
headers: js_util.jsify(headers));
|
||||||
final operation = _cancelableFetch = CancelableOperation.fromFuture(
|
|
||||||
js_util.promiseToFuture(js_util.callMethod(wgs, 'fetch', [uri, init])));
|
|
||||||
|
|
||||||
_response = await operation.value;
|
_response = await js_util
|
||||||
_setReadyState(HttpRequest.HEADERS_RECEIVED);
|
.promiseToFuture(js_util.callMethod(wgs, 'fetch', [uri, init]))
|
||||||
if (_cancelableSend?.isCanceled ?? false) {
|
.onError((error, stackTrace) => null,
|
||||||
|
test: (error) => _abortController?.signal.aborted ?? false);
|
||||||
|
if (_response == null || (_cancelableSend?.isCanceled ?? false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setReadyState(HttpRequest.HEADERS_RECEIVED);
|
||||||
if (status < 200 || status >= 300) {
|
if (status < 200 || status >= 300) {
|
||||||
onErrorController.add(status);
|
onErrorController.add(status);
|
||||||
}
|
}
|
||||||
|
@ -188,9 +208,11 @@ class FetchHttpRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
final result =
|
final result = await js_util
|
||||||
await js_util.promiseToFuture(js_util.callMethod(reader, 'read', []));
|
.promiseToFuture(js_util.callMethod(reader, 'read', []))
|
||||||
if (_cancelableSend?.isCanceled ?? false) {
|
.onError((error, stackTrace) => null,
|
||||||
|
test: (error) => _abortController?.signal.aborted ?? false);
|
||||||
|
if (result == null || (_cancelableSend?.isCanceled ?? false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final value = js_util.getProperty(result, 'value');
|
final value = js_util.getProperty(result, 'value');
|
||||||
|
@ -219,7 +241,7 @@ class FetchHttpRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
void abort() async {
|
void abort() async {
|
||||||
await _cancelableFetch?.cancel();
|
_abortController?.abort();
|
||||||
await _cancelableSend?.cancel();
|
await _cancelableSend?.cancel();
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
@ -228,6 +250,7 @@ class FetchHttpRequest {
|
||||||
onReadyStateChangeController.close();
|
onReadyStateChangeController.close();
|
||||||
onProgressController.close();
|
onProgressController.close();
|
||||||
onErrorController.close();
|
onErrorController.close();
|
||||||
|
_response = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRequestHeader(String name, String value) {
|
void setRequestHeader(String name, String value) {
|
||||||
|
|
Loading…
Reference in New Issue