Обратные вызовы и обещания, живущие вместе в гармонии API

obratnye vyzovy i obeshhaniya zhivushhie vmeste v garmonii api

В этой статье мы узнаем, как обновить API на основе обратного вызова для поддержки Promises.

Во-первых, что такое API или интерфейс прикладного программирования? Его иногда называют a модуль. Это набор методов и переменных, которые разработчики могут использовать в своих программах.

Просмотрите сопроводительный эпизод Real Coding здесь.

Функции обратного вызова

Многие API и модули JavaScript предоставляют конечный параметр в своих методах для так называемого обратного вызова. В большинстве случаев вы увидите это определение как done, next, callbackили cb (Абревиатура от callback). Функции обратного вызова невероятно полезны, поскольку они позволяют другим разработчикам получить больше вашей функции, например обработки ошибок и асинхронных запросов.

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

Нижеследующая функция является простым примером. Его назначение – удвоить параметр x и вернуть его через указанный callback функция. error начинается как null. Если какая-либо из условных проверок не удается, an Error экземпляр назначен error . Тогда если error существует (он не является нулевым или неопределенным), тогда мы не удваиваем x и мы устанавливаем переменную double как null; иначе, x удваивается и назначается в double переменная. После того, как все выполнено, функция doublePositiveOnly вернет метод обратного вызова с первым ссылающимся на параметром error переменная и второй параметр, ссылающийся на double переменная.

function doublePositiveOnly(x, callback) {
  let error
  if ( !x )
    error = new Error('x must be defined')
  if ( typeof x !== 'number' )
    error = new Error('x must be a number')
  if ( x < 0 )
    error = new Error('x must be positive')
    
  const double = error ? null : x * 2
  
  return callback(error, double)
}

Как бы вы использовали эту функцию?

doublePositiveOnly(16, function (err, result) {
  if (err) console.error(err.message)
  console.log(result)
})

Функции обещания

Функции Promise в производстве легко распознаны, поскольку они используются .then и .catch методы возврата информации пользователю. Почти все функции обратного вызова можно заменить промесями, поэтому давайте перестроим нашу doublePositiveOnly метод использования обещаний

function doublePositiveOnly( x ) {
  return new Promise(function (resolve, reject) {
    let error
    if ( !x )
      error = new Error('x must be defined')
    if ( typeof x !== 'number' )
      error = new Error('x must be a number')
    if ( x < 0 )
      error = new Error('x must be positive')
      
    error ? reject(error) : resolve(x * 2)
  })
}

Вышеприведенная функция служит той же цели реализации обратного вызова. Однако эта версия больше не принимает метод обратного вызова в качестве параметра. Вместо этого тоже rejects ошибка или resolves результат. Вы можете использовать этот метод следующим образом:

doublePositiveOnly(16).then(function (result) {
  // do cool stuff with the result
  console.log(result)
}).catch(function (err) {
  // oh no an error! Handle it however you please
  console.error(err.message) 
})

Читаемость функции Promise гораздо более четкая, чем функция обратного вызова, поскольку вы можете легко обработать результат, а также любые потенциальные ошибки. Есть много других функций Promises, которые я здесь не рассматривал, и я советую вам узнать о них как можно больше.

Обратные звонки и обещания вместе

У нас есть обратные звонки и обещания. Они взаимозаменяемы и оба удовлетворяют одинаковые потребности. Теперь рассмотрим сценарий, где у нас есть API, который поддерживает только методы обратного вызова. Этот API загружается 1000 раз и сейчас работает в производстве в бесчисленных программах. Но теперь сопровождающий тоже хочет поддерживать Promises. Могут ли они сделать это, сохраняя поддержку обратного вызова? ДА!

Давайте рассмотрим реализацию обратного вызова doublePositiveOnly еще раз, но теперь тоже с обещанной поддержкой:

function doublePositiveOnly(x, callback) {
  const func = this.doublePositiveOnly
  
  if ( callback === undefined ) {
    return new Promise(function (resolve, reject) {
      func(x, function (err, result) {
        err ? reject(err) : resolve(result)
      })
    })
  }
  
  let error
  if ( !x )
    error = new Error('x must be defined')
  if ( typeof x !== 'number' )
    error = new Error('x must be a number')
  if ( x < 0 )
    error = new Error('x must be positive')
  
  const double = error ? null : x * 2
  
  return callback(error, double)
}

И просто так doublePositiveOnly метод теперь тоже поддерживает обещания. Это работает, поскольку сначала сохраняет ссылку на функцию в func переменная. Затем он проверяет, была ли передана функция обратного вызова. Если нет, возвращается обещание, которое передается вниз x параметр на другой doublePositiveOnly вызова, и включает функцию обратного вызова. Эта функция обратного вызова также rejects или resolves обещание так же, как это делала реализация только с обещанием.

Прекрасным в этом решении является то, что его можно использовать практически где угодно, и вам не нужно редактировать какие-либо части оригинальной функции! Вы можете увидеть это в действии в модуле с названием fastify-jwt, который я недавно сделал. Оба requestVerify и replySign методы поддерживают как обратные вызовы, так и обещания.

Если у вас есть вопросы, обращайтесь!

Вы можете следить за мной на Github и Twitter или посетить мой веб-сайт.

Продолжай хорошо работать.

~Итан Арровуд

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *