Различные обратные вызовы для ошибки или ошибки в качестве первого аргумента?

12

Мы (и чат JS SO) несколько дней назад поговорили с @rlemon о его библиотеке Little-XHR об обработке ошибок.

По сути, мы хотели решить, какой шаблон обработки ошибок следует использовать:

xhr.get({
    // Some parameters, and then
    success: function(data) {},
    failure: function(data) {}
})

Или:

xhr.get({
    // Some parameters, and then
    callback: function(err, data) {}
})

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

Есть ли мнение / преимущество / недостаток в отношении этих двух моделей?

Флориан Маргейн
источник
xhr.get({ ... }, function (err, data) {})По крайней мере, понять шаблон правильно
Raynos

Ответы:

5

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

Я лично предпочитаю

(err, data)потому что это стандартный способ обработки вещей. Это позволяет для композиции функции.

Например after.mapиспользует этот шаблон. Так что код вроде

after.map(["foo.js", "bar.js"], function (fileName, callback) {
    fs.readFile(fileName, function (err, file) {
        callback(err, file)
    })
}, function (err, files) {
    // handle files
})

можно упростить до

after.map(["foo.js", "bar.js", fs.readFile, function (err, files) {
    // handle files
})

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

asyncOperation(options, function (err, data) {
    // not nested inside an object literal
})

Последний подход обратного вызова - хороший подход к знакомству с API.

Еще одним преимуществом является то, что вы можете легко забыть установить errorобработчик в вашем литерале объекта или установить для него какой-либо обработчик ошибок по умолчанию.

Когда вы используете (err, data)его, это напоминает вам о том, как каждый раз эффективно справляться с этой ошибкой.

Raynos
источник
2

Вообще, мне нравится помнить, что явное всегда лучше, чем неявное.

Используя это, я обычно склоняюсь к явным successи failureфункциям - вы точно знаете, с чем имеете дело, когда открываете этот код, - успешно обрабатывает успешно завершенные вызовы, в то время как ошибка относится к вызовам, в которых возникла проблема.

Альтернатива, использующая один метод, займет больше времени для чтения, когда вы собираетесь изменить этот код. Кроме того, вы, вероятно, в конечном итоге что-то вроде этого;

xhr.get({
    callback: function(err, data) {
        if (err) {
            // handle that error somehow
        }
        else {
            // deal with success somehow
        }
    }
})

И такой шаблон становится скучным, быстрым.

Не говоря уже о том, что если вы забудете добавить этот шаблон и, к примеру, вы справляетесь только с успехом, то новый разработчик, вводящий базу кода, может не увидеть проблемы с ней. Но имея явные обратные вызовы об ошибках / успехах, они могли бы довольно быстро увидеть, что вы пропустили errorобратный вызов, и начать работать над способом его обработки или, по крайней мере, выяснить: «Ну, это только обработка успеха - я должен найти способ справиться с ошибками ". Это делает код менее волшебным.

Натан Хоад
источник
Труднее увидеть, что вы пропустили обратный вызов ошибки, и легче увидеть, что вы не обрабатываете первый errпараметр
Raynos
1

Отдельные обратные вызовы

Если xhr.get()вызов успешен, то errявляется избыточным. Если вызов не удался. dataизбыточно Вместо того, чтобы заставлять код клиента проверять состояние одного или другого, не передавайте оба.

Если окажется, что успех может представлять частичный успех, укажите это отдельно. Отказ обычно является вариантом спасения.

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

JBRWilkinson
источник