描述
情况很混乱,我会尽力详细解释一下。
第 1 部分
首先,我创建一个创建者Promise
函数AbortSignal
:
/**
* @template T
* @param {(signal: AbortSignal, resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void} callback
* @returns {Promise<T>}
*/
Promise.withSignal = async function (callback) {
const controller = new AbortController();
const { promise, resolve, reject } = Promise.withResolvers();
try {
callback(controller.signal, resolve, reject);
return await promise;
} finally {
controller.abort();
}
};
请注意,该函数保证完成后Promise
,signal
状态将为aborted
.
第2部分
然后我创建一个异步确认:
const dialogConfirm = document.querySelector(`dialog.pop-up.confirm`);
dialogConfirm.addEventListener(`click`, (event) => {
if (event.target === dialogConfirm) dialogConfirm.close();
});
/**
* @returns {Promise<boolean>}
*/
Window.prototype.confirmAsync = async function () {
dialogConfirm.showModal();
const buttonAccept = dialogConfirm.querySelector(`button.highlight`);
const buttonDecline = dialogConfirm.querySelector(`button.invalid`);
try {
return await Promise.withSignal((signal, resolve, reject) => {
buttonAccept.addEventListener(`click`, (event) => resolve(true), { signal });
buttonDecline.addEventListener(`click`, (event) => resolve(false), { signal });
dialogConfirm.addEventListener(`close`, (event) => resolve(false), { signal });
});
} finally {
dialogConfirm.close();
}
};
我们假设 HTML 附加到页面上
第三部分
下面我创建一个“生成”的类Promise
:
/**
* @template T
*/
class PromiseFactory {
/**
* @param {(resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void} executor
*/
constructor(executor) {
this.#executor = executor;
}
/** @type {(resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void} */
#executor;
/**
* @returns {Promise<T>}
*/
async run() {
const { promise, resolve, reject } = Promise.withResolvers();
await this.#executor.call(promise, resolve, reject);
return promise;
}
/**
* @param {(value: T) => boolean} predicate
*/
async runUntil(predicate) {
while (true) {
try {
const result = await this.run();
if (!predicate(result)) continue;
return result;
} catch {
continue;
}
}
}
}
第 4 部分
最后我把它们放在一起:
/** @type {PromiseFactory<boolean>} */
const factory = new PromiseFactory(async (resolve) => resolve(await window.confirmAsync()));
factory.runUntil(result => {
console.log(result);
return result;
});
这个设计的重点是创造一些可以“重复”Promise
直到达到预期结果的东西。好像这段代码到现在为止还应该打开对话框,直到您单击“接受”。
完整的工作示例:
/**
* @template T
* @param {(signal: AbortSignal, resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void} callback
* @returns {Promise<T>}
*/
Promise.withSignal = async function (callback) {
const controller = new AbortController();
const { promise, resolve, reject } = Promise.withResolvers();
try {
callback(controller.signal, resolve, reject);
return await promise;
} finally {
controller.abort();
}
};
const dialogConfirm = document.querySelector(`dialog.pop-up.confirm`);
dialogConfirm.addEventListener(`click`, (event) => {
if (event.target === dialogConfirm) dialogConfirm.close();
});
/**
* @returns {Promise<boolean>}
*/
Window.prototype.confirmAsync = async function () {
dialogConfirm.showModal();
const buttonAccept = dialogConfirm.querySelector(`button.highlight`);
const buttonDecline = dialogConfirm.querySelector(`button.invalid`);
try {
return await Promise.withSignal((signal, resolve, reject) => {
buttonAccept.addEventListener(`click`, (event) => resolve(true), { signal });
buttonDecline.addEventListener(`click`, (event) => resolve(false), { signal });
dialogConfirm.addEventListener(`close`, (event) => resolve(false), { signal });
});
} finally {
dialogConfirm.close();
}
};
/**
* @template T
*/
class PromiseFactory {
/**
* @param {(resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void} executor
*/
constructor(executor) {
this.#executor = executor;
}
/** @type {(resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void} */
#executor;
/**
* @returns {Promise<T>}
*/
async run() {
const { promise, resolve, reject } = Promise.withResolvers();
await this.#executor.call(promise, resolve, reject);
return promise;
}
/**
* @param {(value: T) => boolean} predicate
*/
async runUntil(predicate) {
while (true) {
try {
const result = await this.run();
if (!predicate(result)) continue;
return result;
} catch {
continue;
}
}
}
}
/** @type {PromiseFactory<boolean>} */
const factory = new PromiseFactory(async (resolve) => resolve(await window.confirmAsync()));
factory.runUntil(result => {
console.log(result);
return result;
});
<dialog class="pop-up confirm">
<button class="highlight">Accept</button>
<button class="invalid">Decline</button>
</dialog>
问题
问题是,如果按 Decline,就会开始无限循环,尽管程序是异步的并且不会冻结,但它仍然是错误的。
我只是不明白为什么我有一个无限循环。
我仍然不知道如何解决它。