Давайте посмотрим на лес сначала, прежде чем смотреть на деревья.
Здесь есть много информативных ответов с большими подробностями, я не буду повторять ни одного из них. Ключ к программированию в JavaScript имеет сначала правильную ментальную модель общего исполнения.
Хорошие новости заключается в том, что, если вы хорошо понимаете этот момент, вам никогда не придется беспокоиться о гоночных условиях. Прежде всего вы должны понимать, как вы хотите упорядочить свой код как по существу ответ на разные дискретные события, и как вы хотите объединить их в логическую последовательность. Вы можете использовать обещания или новые асинхронные / ожидающие более высокие уровни в качестве инструментов для этой цели, или вы можете откатывать свои собственные.
Но вы не должны использовать какие-либо тактические инструменты для решения проблемы, пока вам не понравится актуальная проблемная область. Нарисуйте карту этих зависимостей, чтобы знать, что нужно запускать, когда. Попытка ad-hoc подхода ко всем этим обратным вызовам просто не поможет вам.
Вернув undefined
в ваш блок if( ... === null )
, вы прерываете транзакцию. Таким образом, он никогда не посылает попытку на сервер, никогда не понимает, что локально кэшированное значение не совпадает с удаленным, и никогда не повторяет с обновленным значением (фактическое значение с сервера).
Это подтверждается тот факт, что committed
является false
, а ошибка - null
в вашей функции успеха, которая возникает, если транзакция прерывается.
Сделки работают следующим образом:
null
(наиболее вероятное удаленное значение для этого пути) undefined
прервать транзакцию, в противном случае создать хеш текущего значения (null) и передать это и новое значение (возвращаемое функцией обработки) на сервер Итак, чтобы сделать эту работу, очевидно, что вы не можете прервать транзакцию по первому возвращенному значению.
Одно решение для достижения одного и того же результата - хотя оно связано и не является таким же результативным или подходящим, как просто использование транзакций, как было разработано, - было бы обернуть транзакцию в обратном вызове once('value', ...)
, что убедитесь, что он локализован локально перед запуском транзакции.