Проблема при совместном использовании Promise и AbortController
Описание
Сделал такое "дополнение"...
Promise.withSignal = function (callback) {
const abortController = new AbortController();
const promise = new Promise((resolve, reject) => callback(abortController.signal, resolve, reject));
promise.catch(Function).finally(() => abortController.abort());
return promise;
};
... чтобы облегчить себе жизнь при использовании Promise в слушателях.
Теперь пишу тест для него:
Promise.withSignal = function (callback) {
const abortController = new AbortController();
const promise = new Promise((resolve, reject) => callback(abortController.signal, resolve, reject));
promise.catch(Function).finally(() => abortController.abort());
return promise;
};
// Promise.withSignal should create a controllable promise
void async function () {
const body = document.body;
let counter = 0;
const promise = Promise.withSignal((signal, resolve) => {
body.addEventListener(`click`, (event) => resolve(++counter), { signal });
});
body.click();
if (counter !== 1) console.warn(`Expected 1 for first time`);
await promise;
body.click();
if (counter !== 1) console.warn(`Expected 1 for subsequent times`);
}();
Тест показывает, что функция нифига не работает.
Вопрос
Я никак не пойму, в чем проблема.
К тому же где-то полчаса назад она работала, но выдавала другую проблему, из-за чего я ее чуть-чуть подправил.
Дополнительно 1
Вот минимальный пример использования:
Promise.withSignal = function(callback) {
const abortController = new AbortController();
const promise = new Promise((resolve, reject) => callback(abortController.signal, resolve, reject));
promise.catch(Function).finally(() => abortController.abort());
return promise;
};
void async function () {
const buttonTrue = document.querySelector(`button#true`);
const buttonFalse = document.querySelector(`button#false`);
const choice = await Promise.withSignal((signal, resolve) => {
buttonTrue.addEventListener(`click`, (event) => resolve(true), { signal });
buttonFalse.addEventListener(`click`, (event) => resolve(false), { signal });
});
console.log(`Your choice is ${choice ? `'true'` : `'false'`}. You can't change it anymore`);
}();
<button id="true">True</button>
<button id="false">False</button>
Ответы (1 шт):
Я никак не пойму, в чем проблема
Как я и писал выше - твой "аборт" происходит уже после всех событий. Он в таком варианте бесполезен.
Вот посмотри. Я добавил в твой пример вывод в консоль для демонстрации.
Promise.withSignal = function (callback) {
const abortController = new AbortController();
const promise = new Promise((resolve, reject) => callback(abortController.signal, resolve, reject));
promise
.catch(Function)
.finally(_ => {
console.log('finally')
abortController.abort()
});
return promise;
};
// Promise.withSignal should create a controllable promise
void async function () {
const body = document.body;
let counter = 0;
const promise = Promise.withSignal((signal, resolve) => {
body.addEventListener(`click`, (event) => {
console.log('click', counter)
resolve(++counter)
}, { signal });
});
body.click();
console.log(111, counter)
if (counter !== 1) console.warn(`Expected 1 for first time`);
console.log(222, counter)
await promise;
console.log(333, counter)
body.click();
console.log(444, counter)
if (counter !== 1) console.warn(`Expected 1 for subsequent times`);
}();
Вот мой вариант... Такое ты хотел получить?
Делать "аборт" нужно в нужное время, извини за тавтологию... :)
Promise.withSignal = function (callback) {
const abortController = new AbortController();
const promise = new Promise((resolve, reject) => {
callback(abortController, resolve, reject)
});
promise
.catch(Function)
.finally(_ => {
console.log('finally')
//abortController.abort()
});
return promise;
};
// Promise.withSignal should create a controllable promise
void async function () {
const body = document.body;
let counter = 0;
const promise = Promise.withSignal((abortController, resolve) => {
body.addEventListener(`click`, (event) => {
console.log('click', counter)
resolve(++counter)
abortController.abort()
}, { signal: abortController.signal });
});
body.click();
console.log(111, counter)
if (counter !== 1) console.warn(`Expected 1 for first time`);
console.log(222, counter)
await promise;
console.log(333, counter)
body.click();
console.log(444, counter)
if (counter !== 1) console.warn(`Expected 1 for subsequent times`);
}();
Вот еще вариант придумал... Думаю тебе понравится такой подход. ;)
Promise.withSignal = function (callback) {
const abortController = new AbortController();
const promise = new Promise((resolve, reject) => callback(abortController.signal, resolve, reject));
promise.then(() => abortController.abort(), () => abortController.abort());
return promise;
};
// Promise.withSignal should create a controllable promise
void async function () {
const body = document.body;
let counter = 0;
const promise = Promise.withSignal((signal, resolve) => {
body.addEventListener(`click`, (event) => resolve(++counter), { signal });
});
body.click();
if (counter !== 1) console.warn(`Expected 1 for first time`);
await promise;
body.click();
if (counter !== 1) console.warn(`Expected 1 for subsequent times`);
console.log('Ok', counter)
}();