[javascript] 자바 스크립트 약속-거부와 던지기

이 주제에 대해 여러 기사를 읽었지만 Promise.reject오류와 던지기 사이에 차이가 있는지는 분명하지 않습니다 . 예를 들어

Promise.reject 사용

return asyncIsPermitted()
    .then(function(result) {
        if (result === true) {
            return true;
        }
        else {
            return Promise.reject(new PermissionDenied());
        }
    });

던지기 사용하기

return asyncIsPermitted()
    .then(function(result) {
        if (result === true) {
            return true;
        }
        else {
            throw new PermissionDenied();
        }
    });

내가 선호 throw하는 것은 더 짧기 때문에 단순히 사용하는 것이지만 다른 것보다 이점이 있는지 궁금합니다.



답변

하나를 사용하는 것의 장점 throw은 없지만 작동하지 않는 특정한 경우 가 있습니다. 그러나 이러한 경우는 고칠 수 있습니다.

약속 콜백 내부에 있으면 언제든지을 사용할 수 있습니다 throw. 그러나 다른 비동기 콜백 인 경우을 사용해야합니다 reject.

예를 들어, 이것은 catch를 트리거하지 않습니다.

new Promise(function() {
  setTimeout(function() {
    throw 'or nah';
    // return Promise.reject('or nah'); also won't work
  }, 1000);
}).catch(function(e) {
  console.log(e); // doesn't happen
});

대신에 해결되지 않은 약속과 잡히지 않은 예외가 남게됩니다. 대신을 사용하려는 경우 reject입니다. 그러나 두 가지 방법으로이 문제를 해결할 수 있습니다.

  1. 제한 시간 내에 원래 약속의 거부 기능을 사용하여 :
new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject('or nah');
  }, 1000);
}).catch(function(e) {
  console.log(e); // works!
});

  1. 타임 아웃을 약속함으로써 :
function timeout(duration) { // Thanks joews
  return new Promise(function(resolve) {
    setTimeout(resolve, duration);
  });
}

timeout(1000).then(function() {
  throw 'worky!';
  // return Promise.reject('worky'); also works
}).catch(function(e) {
  console.log(e); // 'worky!'
});


답변

또 다른 중요한 사실이다 reject() 않습 유사한 제어 흐름을 종료 return문을 수행합니다. 반대로 throw제어 흐름은 종료됩니다.

예:

new Promise((resolve, reject) => {
  throw "err";
  console.log("NEVER REACHED");
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));

vs

new Promise((resolve, reject) => {
  reject(); // resolve() behaves similarly
  console.log("ALWAYS REACHED"); // "REJECTED" will print AFTER this
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));


답변

예, 가장 큰 차이점은 거부 는 약속이 거부 된 후에 수행되는 콜백 함수이며 throw 는 비동기 적으로 사용할 수 없다는 것입니다. 거부를 사용하도록 선택한 경우 코드는 비동기 방식으로 계속 정상적으로 실행되지만 throw 는 리졸버 기능 완료를 우선 순위로 둡니다 (이 기능은 즉시 실행 됨).

내가 본 문제를 분명히하는 데 도움이되는 예는 다음과 같이 거부로 Timeout 함수를 설정할 수 있다는 것입니다.

new Promise(_, reject) {
 setTimeout(reject, 3000);
});

위는 던지기로 쓸 수 없었습니다.

작은 예제에서 구별 할 수없는 차이가 있지만보다 복잡한 비동기 개념을 처리 할 때는 둘 사이의 차이가 극심 할 수 있습니다.


답변

TLDR : 함수는 때때로 약속을 반환하고 때로는 예외를 던질 때 사용하기가 어렵습니다. 비동기 함수를 작성할 때 거부 된 약속을 반환하여 신호 실패를 선호합니다.

귀하의 특정 예는 그들 사이의 중요한 차이점을 모호하게합니다 :

약속 체인 에서 오류를 처리하기 때문에 throw 된 예외가 자동으로 변환됩니다. 거부 된 약속 됩니다. 이것은 왜 그들이 상호 교환 가능한 것처럼 보일 수 있는지 설명 할 수 있습니다.

아래 상황을 고려하십시오.

checkCredentials = () => {
    let idToken = localStorage.getItem('some token');
    if ( idToken ) {
      return fetch(`https://someValidateEndpoint`, {
        headers: {
          Authorization: `Bearer ${idToken}`
        }
      })
    } else {
      throw new Error('No Token Found In Local Storage')
    }
  }

비동기 및 동기화 오류 사례를 모두 지원해야하기 때문에 이것은 안티 패턴입니다. 다음과 같이 보일 수 있습니다.

try {
  function onFulfilled() { ... do the rest of your logic }
  function onRejected() { // handle async failure - like network timeout }
  checkCredentials(x).then(onFulfilled, onRejected);
} catch (e) {
  // Error('No Token Found In Local Storage')
  // handle synchronous failure
} 

좋지 않으며 여기에 정확히 어디에 Promise.reject (전 세계적으로 이용 가능한) 구출의 와 효과적으로 차별화됩니다 throw. 리 팩터는 이제 다음과 같습니다.

checkCredentials = () => {
  let idToken = localStorage.getItem('some_token');
  if (!idToken) {
    return Promise.reject('No Token Found In Local Storage')
  }
  return fetch(`https://someValidateEndpoint`, {
    headers: {
      Authorization: `Bearer ${idToken}`
    }
  })
}

이제 catch()네트워크 장애 토큰 부족에 대한 동기 오류 검사에 하나만 사용할 수 있습니다 .

checkCredentials()
      .catch((error) => if ( error == 'No Token' ) {
      // do no token modal
      } else if ( error === 400 ) {
      // do not authorized modal. etc.
      }


답변

시험해 볼만한 예. throw 대신 거부를 사용하려면 isVersionThrow를 false로 변경하십시오.

const isVersionThrow = true

class TestClass {
  async testFunction () {
    if (isVersionThrow) {
      console.log('Throw version')
      throw new Error('Fail!')
    } else {
      console.log('Reject version')
      return new Promise((resolve, reject) => {
        reject(new Error('Fail!'))
      })
    }
  }
}

const test = async () => {
  const test = new TestClass()
  try {
    var response = await test.testFunction()
    return response
  } catch (error) {
    console.log('ERROR RETURNED')
    throw error
  }
}

test()
.then(result => {
  console.log('result: ' + result)
})
.catch(error => {
  console.log('error: ' + error)
})


답변