@@ -29,6 +29,8 @@ import { serializeFetchParameter } from "./serializeFetchParameter.js";
29
29
30
30
const backupFetch = maybe ( ( ) => fetch ) ;
31
31
32
+ function noop ( ) { }
33
+
32
34
export const createHttpLink = ( linkOptions : HttpLink . Options = { } ) => {
33
35
let {
34
36
uri = "/graphql" ,
@@ -106,11 +108,29 @@ export const createHttpLink = (linkOptions: HttpLink.Options = {}) => {
106
108
) ;
107
109
}
108
110
109
- let controller : AbortController | undefined ;
110
- if ( ! options . signal && typeof AbortController !== "undefined" ) {
111
- controller = new AbortController ( ) ;
112
- options . signal = controller . signal ;
111
+ let controller : AbortController | undefined = new AbortController ( ) ;
112
+ let cleanupController = ( ) => {
113
+ controller = undefined ;
114
+ } ;
115
+ if ( options . signal ) {
116
+ // in an ideal world we could use `AbortSignal.any` here, but
117
+ // React Native uses https://github.com/mysticatea/abort-controller as
118
+ // a polyfill for `AbortController`, and it does not support `AbortSignal.any`.
119
+ const abort = controller . abort . bind ( controller ) ;
120
+ options . signal . addEventListener ( "abort" , abort , { once : true } ) ;
121
+ cleanupController = ( ) => {
122
+ controller = undefined ;
123
+ // on cleanup, we need to stop listening to `options.signal` to avoid memory leaks
124
+ options . signal . removeEventListener ( "abort" , abort ) ;
125
+ cleanupController = noop ;
126
+ } ;
127
+ // react native also does not support the addEventListener `signal` option
128
+ // so we have to simulate that ourself
129
+ controller . signal . addEventListener ( "abort" , cleanupController , {
130
+ once : true ,
131
+ } ) ;
113
132
}
133
+ options . signal = controller . signal ;
114
134
115
135
// If requested, set method to GET if there are no mutations.
116
136
const definitionIsMutation = ( d : DefinitionNode ) => {
@@ -181,11 +201,11 @@ export const createHttpLink = (linkOptions: HttpLink.Options = {}) => {
181
201
}
182
202
} )
183
203
. then ( ( ) => {
184
- controller = undefined ;
204
+ cleanupController ( ) ;
185
205
observer . complete ( ) ;
186
206
} )
187
207
. catch ( ( err ) => {
188
- controller = undefined ;
208
+ cleanupController ( ) ;
189
209
handleError ( err , observer ) ;
190
210
} ) ;
191
211
0 commit comments