abortcontroller-polyfill
Advanced tools
Comparing version 1.0.4 to 1.0.5
@@ -5,2 +5,6 @@ 'use strict'; | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -15,25 +19,30 @@ | ||
var AbortSignal = function () { | ||
var Emitter = function Emitter() { | ||
var _this = this; | ||
_classCallCheck(this, Emitter); | ||
var delegate = document.createDocumentFragment(); | ||
var methods = ['addEventListener', 'dispatchEvent', 'removeEventListener']; | ||
methods.forEach(function (method) { | ||
return _this[method] = function () { | ||
return delegate[method].apply(delegate, arguments); | ||
}; | ||
}); | ||
}; | ||
var AbortSignal = function (_Emitter) { | ||
_inherits(AbortSignal, _Emitter); | ||
function AbortSignal() { | ||
_classCallCheck(this, AbortSignal); | ||
this.aborted = false; | ||
this.listeners = []; | ||
var _this2 = _possibleConstructorReturn(this, (AbortSignal.__proto__ || Object.getPrototypeOf(AbortSignal)).call(this)); | ||
_this2.aborted = false; | ||
return _this2; | ||
} | ||
_createClass(AbortSignal, [{ | ||
key: 'addEventListener', | ||
value: function addEventListener(which, callback) { | ||
if (which == 'abort') { | ||
if (this.aborted) { | ||
callback(); | ||
} else { | ||
this.listeners.push(callback); | ||
} | ||
} | ||
} | ||
}]); | ||
return AbortSignal; | ||
}(); | ||
}(Emitter); | ||
@@ -51,5 +60,3 @@ var AbortController = function () { | ||
this.signal.aborted = true; | ||
this.signal.listeners.forEach(function (cb) { | ||
return cb(); | ||
}); | ||
this.signal.dispatchEvent(new Event('abort')); | ||
} | ||
@@ -63,15 +70,24 @@ }]); | ||
var abortableFetch = function abortableFetch(input, init) { | ||
var isAborted = false; | ||
if (init && init.signal) { | ||
init.signal.addEventListener('abort', function () { | ||
isAborted = true; | ||
var abortError = new DOMException('Aborted', 'AbortError'); | ||
// Return early if already aborted, thus avoiding making an HTTP request | ||
if (init.signal.aborted) { | ||
return Promise.reject(abortError); | ||
} | ||
// Turn an event into a promise, reject it once `abort` is dispatched | ||
var cancellation = new Promise(function (_, reject) { | ||
init.signal.addEventListener('abort', function () { | ||
return reject(abortError); | ||
}, { once: true }); | ||
}); | ||
delete init.signal; | ||
// Return the fastest promise (don't need to wait for request to finish) | ||
return Promise.race([cancellation, realFetch(input, init)]); | ||
} | ||
return realFetch(input, init).then(function (r) { | ||
if (isAborted) { | ||
throw new DOMException('Aborted', 'AbortError'); | ||
} | ||
return r; | ||
}); | ||
return realFetch(input, init); | ||
}; | ||
@@ -78,0 +94,0 @@ |
{ | ||
"name": "abortcontroller-polyfill", | ||
"version": "1.0.4", | ||
"version": "1.0.5", | ||
"description": "Browser polyfill for the AbortController DOM API (stub that calls catch, doesn't actually abort request).", | ||
"main": "dist/abortcontroller.js", | ||
"scripts": { | ||
"build": "mkdir dist ; babel src/abortcontroller.js -o dist/abortcontroller.js", | ||
"build": "mkdir -p dist ; babel src/abortcontroller.js -o dist/abortcontroller.js", | ||
"test": "SELENIUM_BROWSER=chrome E2E_HEADLESS=1 ./scripts/wdio-suppress-exitcode", | ||
@@ -9,0 +9,0 @@ "test-chrome": "SELENIUM_BROWSER=chrome ./scripts/wdio-suppress-exitcode", |
@@ -31,2 +31,5 @@ # AbortController "polyfill" | ||
# Contributors | ||
* Martin Olsson | ||
* Jimmy Karl Roland Wärting | ||
@@ -33,0 +36,0 @@ # See also |
@@ -8,16 +8,18 @@ (function(self) { | ||
class AbortSignal { | ||
class Emitter { | ||
constructor() { | ||
const delegate = document.createDocumentFragment(); | ||
const methods = ['addEventListener', 'dispatchEvent', 'removeEventListener']; | ||
methods.forEach(method => | ||
this[method] = (...args) => delegate[method](...args) | ||
); | ||
} | ||
} | ||
class AbortSignal extends Emitter { | ||
constructor() { | ||
super(); | ||
this.aborted = false; | ||
this.listeners = []; | ||
} | ||
addEventListener(which, callback) { | ||
if (which == 'abort') { | ||
if (this.aborted) { | ||
callback(); | ||
} else { | ||
this.listeners.push(callback); | ||
} | ||
} | ||
} | ||
} | ||
@@ -31,3 +33,3 @@ | ||
this.signal.aborted = true; | ||
this.signal.listeners.forEach(cb => cb()); | ||
this.signal.dispatchEvent(new Event('abort')); | ||
} | ||
@@ -38,15 +40,22 @@ } | ||
const abortableFetch = (input, init) => { | ||
let isAborted = false; | ||
if (init && init.signal) { | ||
init.signal.addEventListener('abort', () => { | ||
isAborted = true; | ||
const abortError = new DOMException('Aborted', 'AbortError'); | ||
// Return early if already aborted, thus avoiding making an HTTP request | ||
if (init.signal.aborted) { | ||
return Promise.reject(abortError); | ||
} | ||
// Turn an event into a promise, reject it once `abort` is dispatched | ||
const cancellation = new Promise((_, reject) => { | ||
init.signal.addEventListener('abort', () => reject(abortError), {once: true}); | ||
}); | ||
delete init.signal; | ||
// Return the fastest promise (don't need to wait for request to finish) | ||
return Promise.race([cancellation, realFetch(input, init)]); | ||
} | ||
return realFetch(input, init).then(r => { | ||
if (isAborted) { | ||
throw new DOMException('Aborted', 'AbortError'); | ||
} | ||
return r; | ||
}); | ||
return realFetch(input, init); | ||
}; | ||
@@ -53,0 +62,0 @@ |
const chalk = require('chalk'); | ||
const path = require('path'); | ||
const http = require('http'); | ||
@@ -48,2 +49,28 @@ describe('basic tests', () => { | ||
it('abort before fetch started, verify no HTTP request is made', () => { | ||
const server = http.createServer((req, res) => { | ||
fail('fetch() made an HTTP request despite pre-aborted signal'); | ||
}).listen(0); | ||
const boundListenPort = server.address().port; | ||
browser.url('file://' + path.join(__dirname, 'testpage.html')); | ||
const res = browser.executeAsync(async (boundListenPort, done) => { | ||
setTimeout(() => { | ||
done({name: 'fail'}); | ||
}, 2000); | ||
const controller = new AbortController(); | ||
controller.abort(); | ||
const signal = controller.signal; | ||
try { | ||
await fetch(`http://127.0.0.1:${boundListenPort}`, {signal}); | ||
done({name: 'fail'}); | ||
} catch (err) { | ||
done(err); | ||
} | ||
}, boundListenPort); | ||
const err = res.value; | ||
expect(err.name).toBe('AbortError'); | ||
expect(getJSErrors().length).toBe(0); | ||
server.close(); | ||
}); | ||
it('fetch without aborting', () => { | ||
@@ -68,5 +95,21 @@ browser.url('file://' + path.join(__dirname, 'testpage.html')); | ||
it('fetch without signal set', () => { | ||
browser.url('file://' + path.join(__dirname, 'testpage.html')); | ||
var res = browser.executeAsync(async (done) => { | ||
setTimeout(() => { | ||
done({name: 'fail'}); | ||
}, 2000); | ||
try { | ||
await fetch('http://httpstat.us/200?sleep=50'); | ||
done('PASS'); | ||
} catch (err) { | ||
done(err); | ||
} | ||
}); | ||
expect(res.value).toBe('PASS'); | ||
expect(getJSErrors().length).toBe(0); | ||
}); | ||
}); | ||
function getJSErrors() { | ||
@@ -73,0 +116,0 @@ if (browser.desiredCapabilities.browserName === 'firefox') { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
16380
298
42
8