Если кто-то ищет Linq verson, это работает для меня:
public static IQueryable<BlockVersion> LatestVersionsPerBlock(this IQueryable<BlockVersion> blockVersions)
{
var max_version_per_id = blockVersions.GroupBy(v => v.BlockId)
.Select( v => new { BlockId = v.Key, MaxVersion = v.Max(x => x.Version) } );
return blockVersions.Where( v => max_version_per_id.Any(x => x.BlockId == v.BlockId && x.MaxVersion == v.Version) );
}
Эти два не совсем идентичны. Разница в том, что в первом примере не будет обнаружено исключение, которое было бы выбрано в вашем обработчике success
. Поэтому, если ваш метод должен только возвращать разрешенные обещания, как это часто бывает, вам нужен трейлинг-обработчик catch
(или еще один then
с пустым success
параметром). Конечно, может быть, ваш обработчик then
не сделает ничего, что потенциально может потерпеть неудачу, и в этом случае использование одного 2-параметра then
может быть прекрасным.
Но я считаю, что точка текст, с которым вы связаны, заключается в том, что then
в основном полезен против обратных вызовов в его способности связывать множество асинхронных шагов, и когда вы на самом деле это делаете, 2-параметрическая форма then
тонко не ведет себя так, как ожидалось, по вышеуказанной причине. Это особенно противоречиво, когда используется средняя цепочка.
Как человек, который сделал много сложного асинхронного материала и натолкнулся на такие углы больше, чем я хотел бы признать, я действительно рекомендую избегать этого анти-шаблона и идти с подход отдельного обработчика.
Изучая преимущества и недостатки обоих, мы можем сделать расчетное предположение о том, что подходит для ситуации. Это два основных подхода к реализации обещаний.
Catch Approach
blockquote>some_promise_call() .then(function(res) { logger.log(res) }) .catch(function(err) { logger.log(err) })
Преимущества
- Все ошибки обрабатываются одним уловом block
- Даже выхватывает любое исключение в последующем блоке.
- Цепочка множественных обратных вызовов успеха
Недостатки
- В случае цепочки становится трудно отображать разные сообщения об ошибках.
Подход к успеху / ошибкам
blockquote>some_promise_call() .then(function success(res) { logger.log(res) }, function error(err) { logger.log(err) })
Преимущества
- Вы получаете мелкозернистый контроль ошибок.
- У вас может быть обычная функция обработки ошибок для различных категорий ошибок, таких как ошибка db, ошибка 500 и т. д.
Различия
, вам понадобится еще
- Если вы хотите обработать ошибки, вызванные обратным вызовом успеха
catch
В чем разница?
blockquote>Вызов
.then()
возвращает обещание, которое будет отклонено, если обратный вызов вызывает ошибку. Это означает, что когда ваш успехlogger
не удался, ошибка будет передана в следующий обратный вызов.catch()
, но не с обратным вызовомfail
, который идет вместе сsuccess
.Вот элемент управления блок-схема:
[/g3] [/g4]
Чтобы выразить это в синхронном коде:
// some_promise_call().then(logger.log, logger.log) then: { try { var results = some_call(); } catch(e) { logger.log(e); break then; } // else logger.log(results); }
Второй
log
(что похоже на первый аргумент.then()
) будет выполняться только в том случае, если исключение не было. Маркированный блок и инструкцияbreak
кажутся немного странными, это на самом деле то, что python имеетtry-except-else
для (рекомендуемое чтение!).// some_promise_call().then(logger.log).catch(logger.log) try { var results = some_call(); logger.log(results); } catch(e) { logger.log(e); }
catch
] logger также обрабатывает исключения из вызова журнала регистрации успеха.Так много для разницы.
Я не совсем понимаю его объяснение, как для try and catch
blockquote>Аргумент состоит в том, что обычно вы хотите поймать ошибки на каждом шаге обработки и что вы не должны использовать его в цепочках. Ожидается, что у вас есть только один последний обработчик, который обрабатывает все ошибки. В то время как при использовании «антипаттерна» ошибки в некоторых из обратных вызовов не обрабатываются.
Однако этот шаблон на самом деле очень полезно: когда вы хотите обрабатывать ошибки, которые произошли именно на этом шаге, и вы хотите сделать что-то совершенно другим , когда ошибка не была, т.е. когда ошибка невосстановима. Имейте в виду, что это ветвление вашего потока управления. Конечно, это иногда желательно.
Что случилось с этим следующим:
blockquote>some_promise_call() .then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
Чтобы вам пришлось повторить обратный вызов. Вы предпочитаете
some_promise_call() .catch(function(e) { return e; // it's OK, we'll just log it }) .done(function(res) { logger.log(res); });
Вы также можете использовать
.finally()
для этого.
Вместо слов, хороший пример. Следующий код (если первое обещание разрешено):
Promise.resolve()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
идентично:
Promise.resolve()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)
Но с отклоненным первым обещанием это не идентично:
Promise.reject()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
Promise.reject()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)