최신 정보:
이 게시물의 향후 시청자를 돕기 위해 나는 pluma의 답변 데모를 만들었습니다 .
질문:
나의 목표는 매우 간단 해 보인다.
step(1)
.then(function() {
return step(2);
}, function() {
stepError(1);
return $q.reject();
})
.then(function() {
}, function() {
stepError(2);
});
function step(n) {
var deferred = $q.defer();
//fail on step 1
(n === 1) ? deferred.reject() : deferred.resolve();
return deferred.promise;
}
function stepError(n) {
console.log(n);
}
여기서 문제는 1 단계에서 실패하면 stepError(1)
AND stepError(2)
가 모두 발생한다는 것 입니다. 내가하지 않으면 return $q.reject
다음 stepError(2)
발사,하지만하지 않습니다 step(2)
이해하는 것입니다. 내가하려는 일을 제외하고 모든 것을 성취했습니다.
오류 체인의 모든 함수를 호출하지 않고 거부시 함수를 호출 할 수 있도록 약속을 작성하는 방법은 무엇입니까? 아니면 이것을 달성하는 다른 방법이 있습니까?
여기에 데모가 있으므로 작업이 필요합니다.
최신 정보:
나는 가지 를 해결했다. 여기서는 체인 끝에서 오류를 포착하고 데이터를 전달 reject(data)
하여 오류 기능에서 처리해야 할 문제를 알 수 있습니다. 데이터에 의존하고 싶지 않기 때문에 실제로 요구 사항을 충족시키지 못합니다. 그것은 절름발이이지만 내 경우에는 반환 된 데이터에 의존하여 수행 할 작업을 결정하는 대신 오류 콜백을 함수에 전달하는 것이 더 깨끗합니다.
step(1)
.then(function() {
return step(2);
})
.then(function() {
return step(3);
})
.then(false,
function(x) {
stepError(x);
}
);
function step(n) {
console.log('Step '+n);
var deferred = $q.defer();
(n === 1) ? deferred.reject(n) : deferred.resolve(n);
return deferred.promise;
}
function stepError(n) {
console.log('Error '+n);
}
답변
코드가 예상대로 작동하지 않는 이유는 실제로 생각한 것과 다른 것을 수행하기 때문입니다.
다음과 같은 것이 있다고 가정 해 봅시다.
stepOne()
.then(stepTwo, handleErrorOne)
.then(stepThree, handleErrorTwo)
.then(null, handleErrorThree);
무슨 일이 일어나고 있는지 더 잘 이해하기 위해 try
/ catch
블록 이있는 동기 코드 인 척하십시오 .
try {
try {
try {
var a = stepOne();
} catch(e1) {
a = handleErrorOne(e1);
}
var b = stepTwo(a);
} catch(e2) {
b = handleErrorTwo(e2);
}
var c = stepThree(b);
} catch(e3) {
c = handleErrorThree(e3);
}
onRejected
핸들러 (두 번째 인수 then
) 본질적으로 (a 같은 에러 정정 메커니즘 catch
블록). 에 오류가 발생 handleErrorOne
하면 다음 catch 블록 (catch(e2)
) 등에서 합니다.
이것은 분명히 당신이 의도 한 것이 아닙니다.
무슨 일이 있어도 전체 해결 체인이 실패하기를 원한다고 가정 해 봅시다.
stepOne()
.then(function(a) {
return stepTwo(a).then(null, handleErrorTwo);
}, handleErrorOne)
.then(function(b) {
return stepThree(b).then(null, handleErrorThree);
});
참고 : 거부 handleErrorOne
된 경우에만 호출되기 때문에 현재 위치 를 떠날 수 있습니다 stepOne
(체인의 첫 번째 기능 이므로이 시점에서 체인이 거부되면 해당 기능의 약속 때문일 수 있음을 알고 있습니다) .
중요한 변화는 다른 함수에 대한 오류 처리기가 주요 약속 체인의 일부가 아니라는 것입니다. 대신, 각 단계에는 자체 “서브 체인”이 있으며onRejected
단계가 거부 된 경우에만 호출되는 있습니다 (하지만 주 체인에 직접 도달 할 수는 없음).
이 작품 이유는 둘이다 onFulfilled
하고 onRejected
받는 선택적 인수있는 then
방법은. 약속이 이행되고 (즉, 해결됨) then
체인 의 다음 약속 에 onFulfilled
처리기 가없는 경우 해당 처리기가있는 체인이있을 때까지 체인이 계속됩니다.
이는 다음 두 줄이 동일 함을 의미합니다.
stepOne().then(stepTwo, handleErrorOne)
stepOne().then(null, handleErrorOne).then(stepTwo)
그러나 다음 줄은 위의 두 줄과 동일 하지 않습니다 .
stepOne().then(stepTwo).then(null, handleErrorOne)
Angular의 약속 라이브러리 $q
는 kriskowal의 Q
라이브러리 (더 풍부한 API를 가지고 있지만에서 찾을 수있는 모든 것을 포함 $q
)를 기반으로합니다. GitHub 의 Q API 문서 가 유용 할 수 있습니다. Q는 Promises / A + spec을 구현 합니다.then
은 약속 해결 동작이 정확히 작동 합니다.
편집하다:
또한 오류 처리기에서 체인을 벗어나려면 거부 된 약속을 반환하거나 오류 (거부 된 약속에 자동으로 잡히고 포장됩니다)를 throw해야합니다. 약속을 반환하지 않으면 반환 then
값을 해결 약속으로 래핑합니다.
즉, 아무 것도 반환하지 않으면 가치에 대한 해결 된 약속을 효과적으로 반환하는 것 undefined
입니다.
답변
파티에 늦었지만이 간단한 솔루션이 나를 위해 일했습니다.
function chainError(err) {
return Promise.reject(err)
};
stepOne()
.then(stepTwo, chainError)
.then(stepThreee, chainError);
이를 통해 체인 에서 벗어날 수 있습니다 .
답변
필요한 것은 .then()
특별한 케이스를 시작하고 특별한 케이스를 마무리 하는 반복 체인입니다.
요점은 실패 사례의 단계 번호를 최종 오류 처리기로 리플하는 것입니다.
- 시작 :
step(1)
무조건 호출 합니다. - 반복 패턴 :
.then()
다음 콜백으로 체인 a 를 연결하십시오.- 성공 : 호출 단계 (n + 1)
- 실패 : 이전 지연된 값이 거부 된 값을 던지거나 오류를 다시 발생시킵니다.
- 완료 :
.then()
성공 처리기와 최종 오류 처리기가없는 체인 a
모든 것을 손으로 쓸 수는 있지만 명명 된 일반 함수를 사용하여 패턴을 쉽게 설명 할 수 있습니다.
function nextStep(n) {
return step(n + 1);
}
function step(n) {
console.log('step ' + n);
var deferred = $q.defer();
(n === 3) ? deferred.reject(n) : deferred.resolve(n);
return deferred.promise;
}
function stepError(n) {
throw(n);
}
function finalError(n) {
console.log('finalError ' + n);
}
step(1)
.then(nextStep, stepError)
.then(nextStep, stepError)
.then(nextStep, stepError)
.then(nextStep, stepError)
.then(nextStep, stepError)
.then(null, finalError);});
참조 데모
step()
에서 지연된 항목이 거부되거나 해결되어 체인 n
에서 다음 값의 콜백에 해당 값을 사용할 수있는 방법에 유의하십시오 .then()
. stepError
이 호출 되면 에 의해 처리 될 때까지 오류가 반복해서 다시 발생합니다 finalError
.
답변
거부 할 때 거부 오류를 전달해야하는 경우 체인이 끝날 때까지 거부를 처리하거나 “다시 던져야”하는지를 검사하는 함수에서 단계 오류 핸들러를 랩핑하십시오.
// function mocking steps
function step(i) {
i++;
console.log('step', i);
return q.resolve(i);
}
// function mocking a failing step
function failingStep(i) {
i++;
console.log('step '+ i + ' (will fail)');
var e = new Error('Failed on step ' + i);
e.step = i;
return q.reject(e);
}
// error handler
function handleError(e){
if (error.breakChain) {
// handleError has already been called on this error
// (see code bellow)
log('errorHandler: skip handling');
return q.reject(error);
}
// firs time this error is past to the handler
console.error('errorHandler: caught error ' + error.message);
// process the error
// ...
//
error.breakChain = true;
return q.reject(error);
}
// run the steps, will fail on step 4
// and not run step 5 and 6
// note that handleError of step 5 will be called
// but since we use that error.breakChain boolean
// no processing will happen and the error will
// continue through the rejection path until done(,)
step(0) // 1
.catch(handleError)
.then(step) // 2
.catch(handleError)
.then(step) // 3
.catch(handleError)
.then(failingStep) // 4 fail
.catch(handleError)
.then(step) // 5
.catch(handleError)
.then(step) // 6
.catch(handleError)
.done(function(){
log('success arguments', arguments);
}, function (error) {
log('Done, chain broke at step ' + error.step);
});
콘솔에 표시되는 내용 :
step 1
step 2
step 3
step 4 (will fail)
errorHandler: caught error 'Failed on step 4'
errorHandler: skip handling
errorHandler: skip handling
Done, chain broke at step 4
다음은 작동 코드입니다
https://jsfiddle.net/8hzg5s7m/3/
각 단계마다 특정 처리가있는 경우 래퍼는 다음과 같습니다.
/*
* simple wrapper to check if rejection
* has already been handled
* @param function real error handler
*/
function createHandler(realHandler) {
return function(error) {
if (error.breakChain) {
return q.reject(error);
}
realHandler(error);
error.breakChain = true;
return q.reject(error);
}
}
그럼 네 체인
step1()
.catch(createHandler(handleError1Fn))
.then(step2)
.catch(createHandler(handleError2Fn))
.then(step3)
.catch(createHandler(handleError3Fn))
.done(function(){
log('success');
}, function (error) {
log('Done, chain broke at step ' + error.step);
});
답변
올바르게 이해하면 실패한 단계의 오류 만 표시하고 싶습니까?
첫 번째 약속의 실패 사례를 변경하는 것만 큼 간단합니다.
step(1).then(function (response) {
step(2);
}, function (response) {
stepError(1);
return response;
}).then( ... )
$q.reject()
첫 번째 단계의 실패 사례 로 돌아 가면 해당 약속을 거부하여 2에서 errorCallback이 호출됩니다 then(...)
.
답변
var s = 1;
start()
.then(function(){
return step(s++);
})
.then(function() {
return step(s++);
})
.then(function() {
return step(s++);
})
.then(0, function(e){
console.log(s-1);
});
http://jsbin.com/EpaZIsIp/20/edit
또는 여러 단계에 대해 자동화하십시오.
var promise = start();
var s = 1;
var l = 3;
while(l--) {
promise = promise.then(function() {
return step(s++);
});
}
promise.then(0, function(e){
console.log(s-1);
});
답변
다음과 같이 libs를 사용하십시오.
https://www.npmjs.com/package/promise-chain-break
db.getData()
.then(pb((data) => {
if (!data.someCheck()) {
tellSomeone();
// All other '.then' calls will be skiped
return pb.BREAK;
}
}))
.then(pb(() => {
}))
.then(pb(() => {
}))
.catch((error) => {
console.error(error);
});
