Понимание явного обещания строительства анти паттерна - PullRequest
0 голосов
/ 24 декабря 2018

CertainPerformance выделено в моем предыдущем посте посоветовал мне избегать явной конструкции Promise antipattern со ссылкой на следующий вопрос в stackoverflow

Честно говоря, я новичок в JS и ноде и не очень много использовал обещание.Я пошел и прочитал эту статью, но либо я не мог понять, либо не мог связать, либо, возможно, где-то мое понимание обещаний было расплывчатым / неправильным все вместе

Поэтому я решил задать этот вопрос в новой теме и искатьза помощью.

Так, что я делаю и почему я делаю это

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

Так что это функции, которые я сделал

//Find user by email Address 
const findUserByEmail = (emailAddress) => {
    return new Promise((resolve, reject) => {
     User.findOne({email: emailAddress}).then(response => {
        resolve(res)
      }).catch(error => {
        reject("Error in findUserByEmail", error);
      })
    })
}

//Create User 
const createNewUser = (newUserDetails) => {
    return new Promise((resolve, reject) => {
      new User({
         fullName: newUserDetails.fullName,
         email: newUserDetails.email,
         image: newUserDetails.image,
         gender: newUserDetails.gender,
         age: newUserDetails.age
      }).save().then((response) => {
          resolve(response)
      }).catch((error) => {
          reject("Problem in Creating New User", error)
      })
    })
}

Вопрос 1

Теперь, я предполагаюCertainPerformance заявил о чрезмерном использовании обещаний, потому что я создаю новое обещание return new Promise((resolve, reject) => {, когда уже использую обещания с mongoose User.findOne({email: emailAddress}).then(response => {?

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

const { findUserByEmail } = require("./my_db_query");

, я, вероятно, захочу, чтобы оно вернуло ответ или выдалоошибка в случае ошибки

findUserByEmail("test@example.com").then(/*...*/).catch(/*...*/);

Если я изменю свой фрагмент кода выше без добавления нового обещания

 function findUserByEmail  (email) {
       return User.findOne({email: email}).then(currentUser => currentUser).catch(error => error)
    } 

Вопрос 2

Тогда я, вероятно, не смогу.then и .catch в findUserByEmail("test@example.com")?

И в API-интерфейсе приложения, где я буду вызывать функцию findUserByEmail("test@example.com"), я бы хотел сделать что-то ещеесли есть ошибка (которая будет отличаться для другого случая, и, следовательно, я не могу использовать ее в своей вспомогательной функции).

Вопрос 3

Имеет ли это смысл сейчас делать return new Promise((resolve, reject) => {вместо одного return User.findOne( или я что-то упустил?

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Поскольку .findOne уже возвращает Promise, нет необходимости создавать новый с new Promise - вместо этого, просто цепь на существующую Promise цепь с .then и .catch по мере необходимости.Такие Promise цепочки могут иметь любое число из .then с и .catch с - только то, что вы потребляете Promise с одним .then, не мешает вам использовать одно и то же значение разрешенияв другом месте.Для иллюстрации:

makePromise()
  .then((result) => {
    console.log(result);
    // Returning inside a `.then` will pass along the value to the next `.then`:
    return result;
  })
  .then((result) => {
    // this `result` will be the same as the one above
  });

Другими словами - нет необходимости создавать new Promise каждый раз, когда вы захотите использовать еще один .then.Итак:

Тогда я, вероятно, не смогу .then и .catch в findUserByEmail ("test@example.com")

не правильно -вы действительно можете приковать к концу существующего Promise с таким количеством .then s и .catch es, сколько захотите.

Обратите внимание, что .then, который только возвращает свой параметр и больше ничего не делает (например,поскольку .then(currentUser => currentUser)) излишне - оно вообще ничего не сделает.Также обратите внимание, что .catch поймает Отклонения обещания и преобразуется в решено Promise.Так что если вы сделаете

function findUserByEmail(email) {
  return User.findOne({email: email})
    .then(currentUser => currentUser)
    .catch(error => error)
}

, то catch означает, что абоненты findUserByEmail будут не смогут catch ошибки, потому что любые возможные ошибки были обнаружены в findUserByEmailх catchОбычно рекомендуется разрешить ошибкам просачиваться до вызывающей стороны функции, например, так:

someFunctionThatReturnsPromise('foobar')
  .then((result) => {
    // everything is normal, send the result
    res.send(result);
  })
  .catch((err) => {
    // there was an error, set response status code to 500:
    res.status(500).send('there was an error');
  })

Так, если только ваша findUserByEmail илиcreateNewUser вспомогательные функции необходимо сделать что-то конкретное при возникновении ошибки, вероятно, было бы лучше просто вернуть только Promise:

const findUserByEmail = email => User.findOne(email);
const createNewUser = newUserDetails => new User(newUserDetails).save();

Если ваши вспомогательные функции do нужно что-то делать при возникновении ошибки, а затем, чтобы убедиться, что ошибка передается должным образом вызывающей функции, я бы рекомендовал либо выбросить ошибку внутри catch:

const findUserByEmail = email => User.findOne(email)
  .catch((err) => {
    // error handling - save error text somewhere, do a console.log, etc
    throw err;
  });

, чтобы вы могли catch, когда что-то еще вызывает findUserByEmail.В противном случае, если вы сделаете что-то вроде

const findUserByEmail = email => User.findOne(email)
  .catch((err) => {
    // do something with err
    return err;
  });

, то вызывающий findUserByEmail должен будет проверить внутри .then, если результат действительно является ошибкой, что странно:

findUserByEmail('foo@bar.com')
  .then((result) => {
    if (result instanceof Error) {
      // do something
    } else {
      // No errors
    }
  });

Лучше выдать ошибку в findUserByEmail catch, так что потребитель findUserByEmail может также .catch.

0 голосов
/ 24 декабря 2018

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

Это ошибка, reject("Error in findUserByEmail", error).reject принимает только 1 аргумент, который является причиной отклонения.error будет игнорироваться.Обычно ошибкой является Error объект, а не строка.

Функция может быть изменена на:

   const findUserByEmail = (emailAddress) => {
     return User.findOne({email: emailAddress})
     .then(response => response) // noop
     .catch(error => {
        const readableError = new Error('Error in findUserByEmail');
        readableError.originalError = error;
        throw readableError;
      });
    })
  }

и т. Д.

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

Конструктор Promise оказывает незначительное влияние на производительность.Он вводит еще один уровень вложенности и способствует ад-колбеку - обещания должны помочь избежать его.

Если я изменю свой фрагмент кода выше без добавления нового обещания <...> Тогда я не будуВозможно, вы сможете .then и .catch в findUserByEmail ("test@example.com")?

Нет, обещание может быть связано с then(...) и catch(...) (что является синтаксическим сахаром).для then(null, ...)) столько раз, сколько необходимо, это сильная сторона паттерна.Обратите внимание, что catch(err => { return err }) и catch(err => { throw err }) - это не одно и то же, первый ловит ошибку, а второй ее сбрасывает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...