Это довольно просто сделать, как вы предлагаете, с помощью «токена отмены», с помощью которого «тайм-аут сна» может быть отменен:
// don't do this
function sleep(ms, cancellationToken) {
return new Promise(resolve => function() {
let timeoutRef = setTimeout(resolve, ms);
cancellationToken.cancel = function() {
clearTimout(timeoutRef);
};
});
}
Однако это само по себе не вызовет обещание сна покинуть его pending
состояние, и цепочка обещаний (или ожидающих заявлений), вытекающая из sleep()
, не будет проинформирована об отмене. Прогресс будет зависать.
Этот недостаток можно преодолеть, опять же с помощью токена отмены, но на этот раз тот, который позволяет обещанию sleep()
быть отклоненным, следующим образом ...
// do this
function sleep(ms, cancellationToken) {
return new Promise((resolve, reject) => function() {
cancellationToken.cancel = function() {
reject(new Error('sleep() cancelled'));
};
setTimeout(resolve, ms));
}
}
... и в вызывающей стороне используйте следующее:
async function beginTest() {
try {
const token = {};
const promise = sleep(5000, token);
$('#cancelButton').on('click', token.cancel); // jQuery example, or similar in POJS
await promise;
// ... test code ...
// ... return whatever;
}
catch(error) {
console.log(error.message);
// If button was clicked before the 5000 ms has expired,
// and no other error has been thrown,
// then the log will show "sleep() cancelled".
throw error; // rethrow error to keep beginTest's caller informed.
}
}