Нужно ли мне возвращаться после раннего разрешения / отклонения?



Предположим, у меня есть следующий код.



function divide(numerator, denominator) {
return new Promise((resolve, reject) => {

if(denominator === 0){
reject("Cannot divide by 0");
return; //superfluous?
}

resolve(numerator / denominator);

});
}


Если моя цель-использовать reject чтобы выйти рано, я должен войти в привычку returning сразу после этого, а?

399   5  

5 ответов:

The return цель состоит в том, чтобы прекратить выполнение функции после отклонения и предотвратить выполнение кода после него.

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {

    if (denominator === 0) {
      reject("Cannot divide by 0");
      return; // The function execution ends here 
    }

    resolve(numerator / denominator);
  });
}

в этом случае он предотвращает resolve(numerator / denominator); от выполнения, которое строго не требуется. Тем не менее, по-прежнему предпочтительно прекратить выполнение, чтобы предотвратить возможную ловушку в будущем. Кроме того, рекомендуется предотвратить ненужный запуск кода.

фон

обещание может быть в одном из 3 состояний:

  1. ожидание - начальное состояние. Из ожидания мы можем перейти в одно из других состояний
  2. выполнил - успешная операция
  3. отклонен - неудачная операция

когда обещание выполнено или отклонено, оно будет оставаться в этом состоянии бесконечно долго (поселились). Таким образом, отказ от исполненного обещания или выполнение отвергнутого обещания не будет иметь эффекта.

этот пример фрагмента показывает, что хотя обещание было выполнено после отклонения, оно оставалось отклоненным.

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }

    resolve(numerator / denominator);
  });
}

divide(5,0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

так зачем нам возвращаться?

хотя мы не можем изменить установленное состояние обещания, отклонение или разрешение не остановит выполнение остальной части функции. Функция может содержать код, который будет создавать запутанные результаты. Например:

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }
    
    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

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

остановка выполнения после разрешения / отклонения:

это стандартный материал потока управления JS.

  • после resolve / reject:

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
      return;
    }

    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));
  • вернуться resolve/reject - поскольку возвращаемое значение обратного вызова игнорируется, мы можем сохранить строку, вернув оператор reject/resolve:

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      return reject("Cannot divide by 0");
    }

    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));
  • С помощью блока if/else:

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    } else {
      console.log('operation succeeded');
      resolve(numerator / denominator);
    }
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

Я предпочитаю использовать return параметры, поскольку код более плоский.

общая идиома, которая может быть или не быть вашей чашкой чая, состоит в том, чтобы объединить return С reject, чтобы одновременно отклонить обещание и выйти из функции, так что остальная часть функции, включая resolve не исполнено. Если вам нравится этот стиль, он может сделать ваш код немного более компактный.

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) return reject("Cannot divide by 0");
                           ^^^^^^^^^^^^^^
    resolve(numerator / denominator);
  });
}

это прекрасно работает, потому что конструктор обещать ничего не делает с возвращаемым значением, и в любом случае resolve и reject ничего не возвращать.

та же идиома может быть использована со стилем обратного вызова, показанным в другом ответе:

function divide(nom, denom, cb){
  if(denom === 0) return cb(Error("Cannot divide by zero"));
                  ^^^^^^^^^
  cb(null, nom / denom);
} 

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

технически Он здесь не нужен1 - потому что обещание может быть решена или отклонены, исключительно и только один раз. Первый результат обещания выигрывает, и каждый последующий результат игнорируется. Это разные от обратного вызова в стиле узла.

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

возврат в соответствующее время (или иное использование условных обозначений, чтобы избежать выполнения" другого "случая) уменьшает вероятность случайного запуска кода в недопустимом состоянии или выполнения нежелательных побочных эффектов; и как таковой это делает код менее склонным к" взлому неожиданно".


1 этой технически ответ также зависит от того, что в этом случае код после "возврата", если он будет опущен, не приведет к побочному эффекту. JavaScript будет счастливо делим на ноль и возвращаем либо + бесконечность/ - бесконечность, либо NaN.

ответ Ори уже объясняет, что не надо return но это хорошая практика. Обратите внимание, что конструктор promise безопасен, поэтому он будет игнорировать брошенные исключения, переданные позже в пути, по сути, у вас есть побочные эффекты, которые вы не можете легко наблюдать.

отметим, что returnING early также очень часто встречается в обратных вызовах:

function divide(nom, denom, cb){
     if(denom === 0){
         cb(Error("Cannot divide by zero");
         return; // unlike with promises, missing the return here is a mistake
     }
     cb(null, nom / denom); // this will divide by zero. Since it's a callback.
} 

Итак, хотя это хорошая практика в обещаниях, это требуются с ответами. Некоторые заметки о вашем код:

  • ваш вариант использования гипотетический, на самом деле не используйте обещания с синхронными действиями.
  • конструктор обещаний игнорировать возвращаемые значения. Некоторые библиотеки будут предупреждать, если вы возвращаете неопределенное значение, чтобы предупредить вас об ошибке возвращения туда. Большинство из них не настолько умны.
  • конструктор promise безопасен, он преобразует исключения в отклонения, но, как указывали другие, обещание разрешается один раз.

Если вы не" возвращаетесь " после разрешения/отклонения, плохие вещи (например, перенаправление страницы) могут произойти после того, как вы намеревались его остановить. Источник: я столкнулся с этим.

Comments

    Ничего не найдено.