약속 체인을 끊고 체인이 끊어진 단계에 따라 함수를 호출합니다(거부).
업데이트:
이 게시물의 미래 시청자를 돕기 위해 이 플러마의 답변 데모를 만들었습니다.
질문:.
내 목표는 꽤 간단해 보인다.
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
메커니즘: 수정 메커니즘입니다catch
블록)을 클릭합니다.가 handleErrorOne
, 다음 캐치 블록에 의해 잡힙니다.catch(e2)
입니니다
이건 분명히 네가 의도한 바가 아니야.
예를 들어, 어떤 문제가 발생하더라도 전체 해결 체인이 실패하도록 합니다.
stepOne()
.then(function(a) {
return stepTwo(a).then(null, handleErrorTwo);
}, handleErrorOne)
.then(function(b) {
return stepThree(b).then(null, handleErrorThree);
});
의 : 령 the the the the the the the the는 그대로 둘 수 .handleErrorOne
그것이 존재하는 경우, 왜냐하면 그것은 오직 다음과 같은 경우에만 호출되기 때문입니다.stepOne
rejects(체인의 첫 번째 함수이므로 이 시점에서 체인이 거부된 경우 해당 함수의 약속 때문일 수 있습니다).
중요한 변경은 다른 함수의 오류 핸들러가 주요 약속 체인의 일부가 아니라는 것입니다.각 에는 자체이, '서브체인(sub-chain)'에는 '서브체인(sub-chain)'과 '서브체인(sub-chain)'이 있습니다.onRejected
스텝이 거부되었을 경우에만 호출됩니다(단, 메인 체인으로 직접 도달할 수 없습니다).
잘 는 둘 다 잘되기 입니다.onFulfilled
★★★★★★★★★★★★★★★★★」onRejected
는 옵션 입니다.then
되면), 약속이 이행되면(즉 해결되면), 다음 약속이 이행됩니다.then
onFulfilled
이러한 핸들러를 가진 체인이 존재할 때까지 체인은 계속됩니다.
즉, 다음 2행은 동일합니다.
stepOne().then(stepTwo, handleErrorOne)
stepOne().then(null, handleErrorOne).then(stepTwo)
그러나 다음 행은 위의 두 행과 동일하지 않습니다.
stepOne().then(stepTwo).then(null, handleErrorOne)
라이브러리$q
의 Kriscowal을.Q
API는 API를 , 에서 수 하고 있습니다).$q
) GitHub의 Q API 문서는 도움이 될 수 있습니다.Q는 Promise/A+ 사양을 구현하며, 이는 다음과 같은 방법에 대해 자세히 설명합니다.then
이치노
편집:
또, 에러 핸들러내의 체인을 떼어내려면 , 거부된 약속을 반환하거나 에러를 송신할 필요가 있습니다(이 에러는 자동적으로 검출되어 거부된 약속으로 포장됩니다). 응대하지 않는다then
는 반환값을 해결 약속으로 감싸줍니다.
이 아니라, 반환되는 것이 인 this 、 아 、 무 、 무 、 아 、 promise 、 promise 、 promise 、 promise 、 promise 、 promise promise for 。undefined
.
파티에는 조금 늦었지만, 이 간단한 해결책은 나에게 효과가 있었다.
function chainError(err) {
return Promise.reject(err)
};
stepOne()
.then(stepTwo, chainError)
.then(stepThreee, chainError);
이렇게 하면 사슬에서 벗어날 수 있습니다.
한 것은 입니다..then()
특수 케이스로 시작하는 체인 및 마감하는 특수 케이스가 있는 체인.
요령은 장애 사례의 스텝 번호를 취득하여 최종 에러 핸들러에 전달하는 것입니다.
- : 콜 콜 : 콜
step(1)
★★★★★★★★★★★★★★★★★★. - 패턴: a: 체인 a
.then()
을 사용하다- 성공: 콜 스텝(n+1)
- failure: 이전에 삭제한 값을 던지거나 오류를 다시 던집니다.
- a: 체인 a
.then()
성공 핸들러와 최종 에러 핸들러가 없습니다.
모든 것을 손으로 쓸 수 있지만, 이름 붙여진 일반 함수로 패턴을 쉽게 나타낼 수 있습니다.
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()
스텝의이 은 두 됩니다.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);
});
http://jsbin.com/EpaZIsIp/21/edit
가장 좋은 해결책은 약속 체인에 따라 ES6 waits를 사용하는 것입니다.그런 다음 함수에서 돌아와 나머지 동작을 건너뛸 수 있습니다.
나는 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);
});
비동기/대기 기능을 사용하여 이 문제를 해결하려면 다음 절차를 따릅니다.
(async function(){
try {
const response1, response2, response3
response1 = await promise1()
if(response1){
response2 = await promise2()
}
if(response2){
response3 = await promise3()
}
return [response1, response2, response3]
} catch (error) {
return []
}
})()
에서라도 「」를 반환하는 경우.Promise.reject('something')
을 사용법
promiseOne
.then((result) => {
if (!result) {
return Promise.reject('No result');
}
return;
})
.catch((err) => {
console.log(err);
});
첫 번째 약속이 결과를 반환하지 않으면 콘솔에 '결과 없음'만 표시됩니다.
에러 핸들러를 개별 체인 요소로 스텝 실행에 직접 접속합니다.
// Handle errors for step(1)
step(1).then(null, function() { stepError(1); return $q.reject(); })
.then(function() {
// Attach error handler for step(2),
// but only if step(2) is actually executed
return step(2).then(null, function() { stepError(2); return $q.reject(); });
})
.then(function() {
// Attach error handler for step(3),
// but only if step(3) is actually executed
return step(3).then(null, function() { stepError(3); return $q.reject(); });
});
「」를 사용합니다.catch()
:
// Handle errors for step(1)
step(1).catch(function() { stepError(1); return $q.reject(); })
.then(function() {
// Attach error handler for step(2),
// but only if step(2) is actually executed
return step(2).catch(function() { stepError(2); return $q.reject(); });
})
.then(function() {
// Attach error handler for step(3),
// but only if step(3) is actually executed
return step(3).catch(function() { stepError(3); return $q.reject(); });
});
주의: 이는 기본적으로 OP의 이름을 사용하지만 Pluma가 그의 답변에서 제시한 패턴과 동일합니다.
MDN의 예는 다음과 같습니다.
에는 (이렇게 되어 있습니다.)then(null, onErrorHandler)
이것은 기본적으로 같은 것이다.catch(onErrorHandler)
포획 방법 사용 및 체인
var p1 = new Promise(function(resolve, reject) { resolve('Success'); }); p1.then(function(value) { console.log(value); // "Success!" throw 'oh, no!'; }).catch(function(e) { console.log(e); // "oh, no!" }).then(function(){ console.log('after a catch the chain is restored'); }, function () { console.log('Not fired due to the catch'); }); // The following behaves the same as above p1.then(function(value) { console.log(value); // "Success!" return Promise.reject('oh, no!'); }).catch(function(e) { console.log(e); // "oh, no!" }).then(function(){ console.log('after a catch the chain is restored'); }, function () { console.log('Not fired due to the catch'); });
에러 투척 시 Gotchas
// Throwing an error will call the catch method most of the time var p1 = new Promise(function(resolve, reject) { throw 'Uh-oh!'; }); p1.catch(function(e) { console.log(e); // "Uh-oh!" }); // Errors thrown inside asynchronous functions will act like uncaught errors var p2 = new Promise(function(resolve, reject) { setTimeout(function() { throw 'Uncaught Exception!'; }, 1000); }); p2.catch(function(e) { console.log(e); // This is never called }); // Errors thrown after resolve is called will be silenced var p3 = new Promise(function(resolve, reject) { resolve(); throw 'Silenced Exception!'; }); p3.catch(function(e) { console.log(e); // This is never called });
해결되면
//Create a promise which would not call onReject var p1 = Promise.resolve("calling next"); var p2 = p1.catch(function (reason) { //This is never called console.log("catch p1!"); console.log(reason); }); p2.then(function (value) { console.log("next promise's onFulfilled"); /* next promise's onFulfilled */ console.log(value); /* calling next */ }, function (reason) { console.log("next promise's onRejected"); console.log(reason); });
Sequential Promise 모듈 사용
의도
각 작업의 현재 인덱스를 순차적으로 추적하면서 요청을 순차적으로 실행하는 모듈을 제공합니다.명령 패턴에서 작업을 정의하여 유연성을 확보합니다.
참가자
- 콘텍스트:멤버 메서드가 작업을 수행하는 개체입니다.
- 시퀀셜 프로미스:정의하다
execute
각 작업을 체인 및 추적하는 방법.시퀀셜 프로미스: Promise-Chain(프로미스 체인) - 호출자: 컨텍스트와 액션을 제공하는 Sequential Promise 인스턴스를 만들고 해당 인스턴스를 호출합니다.
execute
각 작업에 대한 옵션의 순서형 목록을 전달하면서 메서드를 지정합니다.
결과들
Promise 해결의 순서형 동작이 필요한 경우 Sequential Promise를 사용합니다.Sequential Promise는 약속이 거부된 지수를 추적합니다.
실행
clear();
var http = {
get(url) {
var delay = Math.floor( Math.random() * 10 ), even = !(delay % 2);
var xhr = new Promise(exe);
console.log(`REQUEST`, url, delay);
xhr.then( (data) => console.log(`SUCCESS: `, data) ).catch( (data) => console.log(`FAILURE: `, data) );
function exe(resolve, reject) {
var action = { 'true': reject, 'false': resolve }[ even ];
setTimeout( () => action({ url, delay }), (1000 * delay) );
}
return xhr;
}
};
var SequentialPromise = new (function SequentialPromise() {
var PRIVATE = this;
return class SequentialPromise {
constructor(context, action) {
this.index = 0;
this.requests = [ ];
this.context = context;
this.action = action;
return this;
}
log() {}
execute(url, ...more) {
var { context, action, requests } = this;
var chain = context[action](url);
requests.push(chain);
chain.then( (data) => this.index += 1 );
if (more.length) return chain.then( () => this.execute(...more) );
return chain;
}
};
})();
var sequence = new SequentialPromise(http, 'get');
var urls = [
'url/name/space/0',
'url/name/space/1',
'url/name/space/2',
'url/name/space/3',
'url/name/space/4',
'url/name/space/5',
'url/name/space/6',
'url/name/space/7',
'url/name/space/8',
'url/name/space/9'
];
var chain = sequence.execute(...urls);
var promises = sequence.requests;
chain.catch( () => console.warn(`EXECUTION STOPPED at ${sequence.index} for ${urls[sequence.index]}`) );
// console.log('>', chain, promises);
기스트
언급URL : https://stackoverflow.com/questions/20714460/break-promise-chain-and-call-a-function-based-on-the-step-in-the-chain-where-it
'programing' 카테고리의 다른 글
MongoDB: 설치된 MongoDB의 정확한 버전을 찾는 방법 (0) | 2023.03.10 |
---|---|
json 필드 유형 postgresql에서 null 값을 쿼리하는 방법 (0) | 2023.03.10 |
개체 문자열을 JSON으로 변환 (0) | 2023.03.10 |
만약...엘세...을 사용할 수 있습니까?리액트 렌더 함수에 있는 문? (0) | 2023.03.10 |
Wordpress에서 session_start를 사용하는 방법 (0) | 2023.03.10 |