Может ли распознаватель/отклонитель обещаний вызвать свою противоположность?

Если у нас есть обещание, подобное следующему, каковы ответы на вопросы в его комментариях?

p.then(function ok () {
    // Can we get err() to trigger from inside here?
}, function err () {
    // Can we get ok() to trigger from inside here?
});

Я знаю, что можно присоединить новый then, который может ждать результатов или отменить результаты p, но мне интересно, предполагая, что p является константой, могут ли условия также рекурсивно вызывать друг друга (и без назначения функций для переменные и вызов их по имени)...

ОБНОВЛЕНИЕ

Мой вариант использования выглядит следующим образом.

В IndexedDB при открытии базы данных вы можете прослушивать следующее:

db.onsuccess = ...
db.onerror = ...
db.onblocked = ...

db.js, библиотека, которую я расширяю, чтобы удовлетворить свои потребности, добавляет эти события с обещанием API, так что успех разрешает обещание, а ошибки или блокировка отклоняют его.

Обычным вариантом использования для прослушивания блокировки будет закрытие соединения с базой данных, которое вызывает блокировку, после чего IndexedDB автоматически вызовет onsuccess. Проблема в том, что если мы рассматриваем onblocked как отклонение, у него, по-видимому, нет возможности повторно запустить условие разрешения (т. е. onsuccess). Чтобы обойти это, я могу вместо этого предоставить блокировку в качестве обратного вызова, но мне было интересно, есть ли способ сделать это исключительно с использованием подхода Promises, поскольку технически ошибка больше не будет ошибкой и хотелось бы чтобы дать возможность исходному обратному вызову разрешения возобновиться с его обработкой успеха.


person Brett Zamir    schedule 31.10.2015    source источник
comment
Привет, Бретт. Я удалил свой ответ, так как после того, как вы обновили его, он перестал быть актуальным. Таким образом, я удалил ответ следующего содержания: Это вопрос обработчика! после обработки вашей ошибки и возврата чего-либо, если вы свяжете свое обещание, вы вернетесь в цикле (разрешить, отклонить) – Anonymous0day 1 мин назад   -  person james emanon    schedule 31.10.2015
comment
Извините за путаницу. Ваш комментарий будет работать для среднего варианта использования, но я хочу знать, могу ли я избежать избыточности добавления в цепочку, когда мне нужно только условно вернуться к нормальному состоянию после ошибки (или наоборот).   -  person Brett Zamir    schedule 31.10.2015
comment
Ваш вопрос хороший, я надеюсь, что кто-нибудь ответит на него - мне тоже любопытно.   -  person james emanon    schedule 31.10.2015
comment
Не очень «понятно», но как только мы поймем, этот ответ может быть полезен!   -  person Anonymous0day    schedule 31.10.2015


Ответы (2)


Можем ли мы заставить err() срабатывать от ok?
Можем ли мы заставить ok() срабатывать от err?

Нет. спецификация обещаний требует, чтобы вызывался не более одного из двух обработчиков then. Если обещание выполняется, первое вызывается, если обещание отвергает второе, а обещание не может выполнять обе функции.

Таким образом, хотя вы можете легко создать две именованные функции и вызывать друг друга вручную, программно невозможно вызвать обещание для вызова другого.

Мой вариант использования выглядит следующим образом […]

То, что вы на самом деле, кажется, ищете, это

db.open().catch(function(err) {
    if (err.isBlocking)
        return db.closeAndWaitForNextSuccess(err.blocker); // get another promise
    else
        throw err;
}).then(function ok(res) {
    …
});
person Bergi    schedule 31.10.2015
comment
В вашем примере я понял, что могу еще больше упростить его, вернув новое обещание, резюме, как часть исходного объекта err, чтобы пользователь мог просто добавить return err.resume после закрытия существующих соединений. Это обещание, если оно используется, перезапишет существующие onsuccess и onerror (которые больше не будут работать для разрешения/отклонения из-за того, что onblocked уже вызвало отклонение), так что onsuccess откроет базу данных с использованием исходных параметров. Мне нужно перезаписать, а не создавать новый запрос, поскольку старый запрос все еще может запускать все, что к нему прикреплено onsuccess. - person Brett Zamir; 31.10.2015
comment
@BrettZamir: Юпп, звучит как отличный шаблон. - person Bergi; 31.10.2015

Поскольку вы указываете обработчик ошибок в качестве второго параметра для .then, семантически это означает, что он сработает только в том случае, если обещание «p» будет отклонено. Таким образом, эти два пути являются взаимоисключающими. Это также означает, что если внутри обработчика "ok" вы выдаете ошибку, она НЕ будет обнаружена функцией "err".

Напротив, если бы ваш код использовал .catch, он бы поймал как ошибку, всплывающую из-за отклонения промиса, так и и внутри обработчика успеха. Итак, если у вас было это:

p.then(function () {
    throw new Error("Within the .then");
}).catch(function (error) {
    console.log(error);
});

Он всегда будет регистрировать ошибку на консоли, независимо от того, был ли p разрешен или отклонен.

Итак, на ваш первый вопрос: обработчик ok может вызвать функцию err, IF вместо выполнения .then с двумя аргументами вы делаете .then(successHandler).catch(errorHandler). Но на второй вопрос «нет», несмотря ни на что — нет логического пути ни от обработчика ошибок, ни от «уловки» к пути, который был явно пропущен из-за отказа.

Обновление на основе обновленного описания вопроса:

Предполагая, что вы получаете какой-то индикатор в «улове» о том, почему произошла ошибка (и следует ли вам действительно отклонить или следует продолжать, как если бы это было успешно), нет никаких причин, по которым вы не могли бы вызвать ту же функцию, что и вы бы для успеха. Просто у него будет две точки входа:

p.then(successHandler, failureHandler)
 .then( /* other stuff if you want to chain */ )
 .catch(function(e) {
    // catch-all handler just in case
 })

function successHandler(data) {
    // Do something. Note that to avoid 
    // "breaking the promise chain", the code here
    // should either be all-synchronous or return another promise.
}

function failureHandler(error) {
    if (error.wasDueToBlocking()) {
        return successHandler(error.partialData);
    } else {
        // handle the true error. Again, to avoid 
        // "breaking the promise chain", the code here
        // should either be all-synchronous or return another promise.
    }
}

Обновление 2 на основе требования не создавать отдельные именованные функции/переменные

Я не совсем понимаю, почему вам не нужны именованные функции, и подход, который я собираюсь показать, возможно, немного странный. Но, возможно, вы могли бы сделать это вместо этого, когда обработчик успеха не делает ничего, кроме цепочки к реальному общему обработчику.

p.then(function(data) {
    return {goOn: true, data: data};
 }, function(error) {
    if (error.wasDueToBlocking()) {
        return {goOn: true, data: error.partialData};
    } else {
        // Do some errorHandling logic
        return {goOn: false};
    }
 }
 .then(function(passedThroughData) {
    if (passedThroughData.goOn) {
        // Do something with it.
        // Otherwise ignore, since error handler
        // already took care of whatever it needed above
    }
 })
 .then(function() {
    // whatever you wanted to happen next
 })
 .catch(function(e) {
    // catch-all handler just in case
 })
person Michael Zlatkovsky - Microsoft    schedule 31.10.2015
comment
+1, так как это соответствует моему предполагаемому значению, и да, я понимаю, что добавленный catch (как особый вариант then) может сработать. - person Brett Zamir; 31.10.2015
comment
Что касается семантики, я работаю с API IndexedDB, который использует обещания для установления соединений с базой данных, и API в настоящее время вызывает отклонение обещания при обнаружении ошибок или блокирующих событий. В случае блокировки, если пользователь закроет базу данных в блокирующей (отклоняющей) ветке, в идеале он сможет восстановиться, и в таком случае, я думаю, имеет смысл вернуться к утвердительному разрешению исходного обещания (тогда как если бы это была обычная ошибка, она могла бы нормально продолжить цепочку). - person Brett Zamir; 31.10.2015
comment
@BrettZamir, вы ищете рекурсивное обещание? - person Anonymous0day; 31.10.2015
comment
@BrettZamir, посмотрите мое обновление ответа на основе вашего обновленного варианта использования. - person Michael Zlatkovsky - Microsoft; 31.10.2015
comment
Извините, я искал альтернативу, чтобы избежать этого, согласно словам, без присвоения функций переменным и вызова их по имени. (Я имею в виду также включить объявления обычных функций, но упомянутые переменные, поскольку ссылка на именованные функции может сбивать с толку, поскольку я уже назвал встроенные функции.) - person Brett Zamir; 31.10.2015
comment
Возможно, обещания просто не предназначены для работы как обработчики, которые могут запускаться несколько раз и по мере необходимости. Возможно, его следует добавить к случаям анти-шаблонов, как это обсуждалось на taoofcode.net/promise-anti. -шаблоны . Тем не менее, я думаю, было бы удобно иметь возможность сослаться на другую ветку. - person Brett Zamir; 31.10.2015
comment
См. мое обновление 2, основанное на требовании не создавать автономные именованные функции/переменные. Хотя да, я думаю, что это больше связано с анти-шаблоном... Но для академического любопытства, здесь идет :-) - person Michael Zlatkovsky - Microsoft; 31.10.2015
comment
Цените усилия, и ваш ответ имеет некоторое сходство с принятым ответом, но, помимо того, что он более краток, я думаю, что мне нужно новое обещание, потому что у меня еще нет фактических данных о событии блокировки. - person Brett Zamir; 31.10.2015