Что является эквивалентом не вызова обратного вызова, когда внутри асинхронной функции?
Перед асинхронным ожиданием / ожиданием, когда мой код использовал обратные вызовы, я мог сделать три вещи: (1) вызвать обратный вызов с результатом, (2) вызвать обратный вызов с ошибкой или (3) вообще не вызывать обратный вызов.
Случай (3) использовался в таких ситуациях: скажем, у вас есть кнопка масштабирования, и пользователь может щелкнуть ее, чтобы отобразить изображение с более высоким разрешением, и это асинхронный процесс. Если пользователь снова нажимает кнопку масштабирования, то первый рендер больше не актуален, и его можно отменить, чтобы запустить рендеринг нового уровня масштабирования. Я обработал это, возвращаясь изнутри функции без вызова обратного вызова, например
if (process.wasCanceled()) {
return;
}
// ...
callback(someResult);
С помощью async/await вы можете сделать только две вещи: вернуть или выбросить. В настоящее время я использую команду throw, чтобы указать, что операция была отменена, поскольку возврат может ошибочно указывать на то, что восходящие процессы должны продолжать работать. Но проблема с броском состоит в том, что все вызывающие абоненты должны знать, что это на самом деле не ошибка, и поэтому им, возможно, потребуется проверить тип ошибки.
У меня была еще одна безумная идея - создать обещание, которое никогда не вернется. Например await never()
где функция определяется так:
async function never () {
return new Promise(function () {});
}
Это своего рода эквивалент отказа от вызова обратного вызова.
Но я не знаю, будет ли это просто пропускать память снова и снова.
Есть ли лучший эквивалент без недостатков, о которых я говорил выше?
1 ответ
Если это абсолютно необходимо, вы можете дождаться обещания, которое никогда не вернется. Это эквивалент не вызова обратного вызова.
async function never () {
return new Promise(function () {});
}
async function op (process) {
// ...
if (process.wasCanceled()) await never();
// ...
}
Согласно этим ответам, это будет сборщик мусора, потому что возвращенное обещание никогда не используется и в аргументе функции обещания нет никаких подключений к куче.
Никогда не выполненные обещания вызывают утечку памяти?
Являются ли JavaScript вечно ожидающие обещания плохими?
Однако это, скорее всего, не то, что вы хотите сделать, так как вызывающие абоненты могут знать, что их работа была отменена. Если операция была инициирована пользователем через пользовательский интерфейс, то да, отмена без уведомления вызывающего абонента, вероятно, в порядке, но если операция была инициирована программно и отменена каким-либо другим способом, например, пользователем, то код вызова должен знать что, так что он может попробовать еще раз, или очистить ресурсы.
По этой причине решение состоит в том, чтобы выдать ошибку определенного класса, чтобы вызывающая сторона могла обнаружить, что процесс был отменен. Например
class ProcessCanceledError extends Error {
...
}
async function render (process) {
while (...) {
// do some rendering
await delay(20);
if (process.wasCanceled()) throw new ProcessCanceledError();
}
}
var zoomProcess;
async function zoom () {
let process = new Process();
if (zoomProcess != null && !zoomProcess.isDone()) {
zoomProcess.cancel();
}
try {
await render();
} catch (e) {
// or you could do e.process === process
if (e instanceof ProcessCanceledError &&
process.wasCanceled() // make sure it was actually ours
) {
// this assumes we are a top level function
// otherwise, you would want to propagate the error to caller's caller
return;
}
throw e;
}
}