programing

약속 체인을 끊고 체인이 끊어진 단계에 따라 함수를 호출합니다(거부).

javajsp 2023. 3. 10. 21:06

약속 체인을 끊고 체인이 끊어진 단계에 따라 함수를 호출합니다(거부).

업데이트:

이 게시물의 미래 시청자를 돕기 위해 이 플러마의 답변 데모를 만들었습니다.

질문:.

내 목표는 꽤 간단해 보인다.

  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.rejectstepError(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그것이 존재하는 경우, 왜냐하면 그것은 오직 다음과 같은 경우에만 호출되기 때문입니다.stepOnerejects(체인의 첫 번째 함수이므로 이 시점에서 체인이 거부된 경우 해당 함수의 약속 때문일 수 있습니다).

중요한 변경은 다른 함수의 오류 핸들러가 주요 약속 체인의 일부가 아니라는 것입니다.각 에는 자체이, '서브체인(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을.QAPI는 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