-
-
Notifications
You must be signed in to change notification settings - Fork 11k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(fetch): optimize signals composing logic; (#6582)
- Loading branch information
1 parent
ee208cf
commit df9889b
Showing
4 changed files
with
98 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,48 @@ | ||
import CanceledError from "../cancel/CanceledError.js"; | ||
import AxiosError from "../core/AxiosError.js"; | ||
import utils from '../utils.js'; | ||
|
||
const composeSignals = (signals, timeout) => { | ||
let controller = new AbortController(); | ||
const {length} = (signals = signals ? signals.filter(Boolean) : []); | ||
|
||
let aborted; | ||
if (timeout || length) { | ||
let controller = new AbortController(); | ||
|
||
const onabort = function (cancel) { | ||
if (!aborted) { | ||
aborted = true; | ||
unsubscribe(); | ||
const err = cancel instanceof Error ? cancel : this.reason; | ||
controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err)); | ||
} | ||
} | ||
let aborted; | ||
|
||
let timer = timeout && setTimeout(() => { | ||
onabort(new AxiosError(`timeout ${timeout} of ms exceeded`, AxiosError.ETIMEDOUT)) | ||
}, timeout) | ||
const onabort = function (reason) { | ||
if (!aborted) { | ||
aborted = true; | ||
unsubscribe(); | ||
const err = reason instanceof Error ? reason : this.reason; | ||
controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err)); | ||
} | ||
} | ||
|
||
const unsubscribe = () => { | ||
if (signals) { | ||
timer && clearTimeout(timer); | ||
let timer = timeout && setTimeout(() => { | ||
timer = null; | ||
signals.forEach(signal => { | ||
signal && | ||
(signal.removeEventListener ? signal.removeEventListener('abort', onabort) : signal.unsubscribe(onabort)); | ||
}); | ||
signals = null; | ||
onabort(new AxiosError(`timeout ${timeout} of ms exceeded`, AxiosError.ETIMEDOUT)) | ||
}, timeout) | ||
|
||
const unsubscribe = () => { | ||
if (signals) { | ||
timer && clearTimeout(timer); | ||
timer = null; | ||
signals.forEach(signal => { | ||
signal.unsubscribe ? signal.unsubscribe(onabort) : signal.removeEventListener('abort', onabort); | ||
}); | ||
signals = null; | ||
} | ||
} | ||
} | ||
|
||
signals.forEach((signal) => signal && signal.addEventListener && signal.addEventListener('abort', onabort)); | ||
signals.forEach((signal) => signal.addEventListener('abort', onabort)); | ||
|
||
const {signal} = controller; | ||
const {signal} = controller; | ||
|
||
signal.unsubscribe = unsubscribe; | ||
signal.unsubscribe = () => utils.asap(unsubscribe); | ||
|
||
return [signal, () => { | ||
timer && clearTimeout(timer); | ||
timer = null; | ||
}]; | ||
return signal; | ||
} | ||
} | ||
|
||
export default composeSignals; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import assert from 'assert'; | ||
import composeSignals from '../../../lib/helpers/composeSignals.js'; | ||
|
||
describe('helpers::composeSignals', () => { | ||
before(function () { | ||
if (typeof AbortController !== 'function') { | ||
this.skip(); | ||
} | ||
}); | ||
|
||
it('should abort when any of the signals abort', () => { | ||
let called; | ||
|
||
const controllerA = new AbortController(); | ||
const controllerB = new AbortController(); | ||
|
||
const signal = composeSignals([controllerA.signal, controllerB.signal]); | ||
|
||
signal.addEventListener('abort', () => { | ||
called = true; | ||
}); | ||
|
||
controllerA.abort(new Error('test')); | ||
|
||
assert.ok(called); | ||
}); | ||
|
||
it('should abort on timeout', async () => { | ||
const signal = composeSignals([], 100); | ||
|
||
await new Promise(resolve => { | ||
signal.addEventListener('abort', resolve); | ||
}); | ||
|
||
assert.match(String(signal.reason), /timeout 100 of ms exceeded/); | ||
}); | ||
|
||
it('should return undefined if signals and timeout are not provided', async () => { | ||
const signal = composeSignals([]); | ||
|
||
assert.strictEqual(signal, undefined); | ||
}); | ||
}); |