모든 약속이 해결 될 때까지 기다리십시오.


107

그래서 길이를 알 수없는 약속 체인이 여러 개있는 상황이 있습니다. 모든 CHAINS가 처리되었을 때 몇 가지 작업을 실행하고 싶습니다. 그게 가능할까요? 다음은 예입니다.

app.controller('MainCtrl', function($scope, $q, $timeout) {
    var one = $q.defer();
    var two = $q.defer();
    var three = $q.defer();

    var all = $q.all([one.promise, two.promise, three.promise]);
    all.then(allSuccess);

    function success(data) {
        console.log(data);
        return data + "Chained";
    }

    function allSuccess(){
        console.log("ALL PROMISES RESOLVED")
    }

    one.promise.then(success).then(success);
    two.promise.then(success);
    three.promise.then(success).then(success).then(success);

    $timeout(function () {
        one.resolve("one done");
    }, Math.random() * 1000);

    $timeout(function () {
        two.resolve("two done");
    }, Math.random() * 1000);

    $timeout(function () {
        three.resolve("three done");
    }, Math.random() * 1000);
});

이 예 $q.all()에서는 임의의 시간에 해결 될 약속 1, 2, 3에 대한 a 를 설정했습니다 . 그런 다음 1과 3의 끝에 약속을 추가합니다. all모든 체인이 해결되면 해결 하기 를 원합니다 . 이 코드를 실행할 때의 출력은 다음과 같습니다.

one done 
one doneChained
two done
three done
ALL PROMISES RESOLVED
three doneChained
three doneChainedChained 

체인이 해결 될 때까지 기다리는 방법이 있습니까?

답변:


161

모든 체인이 해결되면 모든 것이 해결되기를 바랍니다.

물론, 각 체인의 약속을 all()초기 약속 대신에 전달하십시오 .

$q.all([one.promise, two.promise, three.promise]).then(function() {
    console.log("ALL INITIAL PROMISES RESOLVED");
});

var onechain   = one.promise.then(success).then(success),
    twochain   = two.promise.then(success),
    threechain = three.promise.then(success).then(success).then(success);

$q.all([onechain, twochain, threechain]).then(function() {
    console.log("ALL PROMISES RESOLVED");
});

2
최악의 두려움을 확인 해주셔서 감사합니다. 이제 마지막 약속을 할 방법을 찾아야합니다.
jensengar 2014

그것의 문제는 무엇입니까? 체인이 동적으로 구성되어 있습니까?
Bergi

정확히 내 문제. 프로 미스 체인을 동적으로 생성하려고하는데 체인이 완료되면 뭔가를하고 싶습니다.
jensengar

코드를 보여줄 수 있습니까 (새 질문을 할 수도 있음)? Q.all실행 된 후에 체인에 추가 된 항목이 있습니까? 그렇지 않으면 사소해야합니까?
Bergi

코드를 보여 드리고 싶지만 아직 작성을 완료하지는 않았지만 최선을 다해 설명하겠습니다. 수행해야하는 "작업"목록이 있습니다. 이러한 작업에는 관련된 하위 작업의 여러 수준이있을 수 있습니다. 모든 작업과 하위 작업이 완료되면 무언가를 할 수 있기를 바랍니다. 여러 개의 $q.alls 가있을 수 있지만 해결 프로세스를 시작하면 새로운 작업 / 약속이 연결되지 않습니다.
jensengar

16

허용 대답은 올바른 것입니다. 에 익숙하지 않은 사람들에게 좀 더 자세히 설명하는 예제를 제공하고 싶습니다 promise.

예:

내 예에서는 콘텐츠를 렌더링하기 전에 사용 가능한 경우 태그 의 src속성을 img다른 미러 URL 로 교체해야 합니다.

var img_tags = content.querySelectorAll('img');

function checkMirrorAvailability(url) {

    // blah blah 

    return promise;
}

function changeSrc(success, y, response) {
    if (success === true) {
        img_tags[y].setAttribute('src', response.mirror_url);
    } 
    else {
        console.log('No mirrors for: ' + img_tags[y].getAttribute('src'));
    }
}

var promise_array = [];

for (var y = 0; y < img_tags.length; y++) {
    var img_src = img_tags[y].getAttribute('src');

    promise_array.push(
        checkMirrorAvailability(img_src)
        .then(

            // a callback function only accept ONE argument. 
            // Here, we use  `.bind` to pass additional arguments to the
            // callback function (changeSrc).

            // successCallback
            changeSrc.bind(null, true, y),
            // errorCallback
            changeSrc.bind(null, false, y)
        )
    );
}

$q.all(promise_array)
.then(
    function() {
        console.log('all promises have returned with either success or failure!');
        render(content);
    }
    // We don't need an errorCallback function here, because above we handled
    // all errors.
);

설명:

AngularJS 문서에서 :

then방법 :

then (successCallback, errorCallback, notifyCallback) – 약속이 언제 해결되거나 거부되었는지에 관계없이 결과가 제공되는 즉시 성공 또는 오류 콜백 중 하나를 비동기 적으로 호출합니다. 콜백은 단일 인수 ( 결과 또는 거부 이유) 로 호출됩니다 .

$ q.all (약속)

여러 약속을 모든 입력 약속이 해결 될 때 해결되는 단일 약속으로 결합합니다.

promisesPARAM는 약속의 배열 일 수있다.

정보 bind(), 자세한 정보 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind


then메서드 $q.all에는 반환 된 promise의 배열이 제공되므로 에 약속을 추가 할 때 then호출하는 대신 해당 배열을 반복하고 배열의 각 항목을 호출 then할 수 있습니다 promise_array.
nick

4

최근 에이 문제가 있었지만 알 수없는 수의 promise가 있습니다 .jQuery.map ()을 사용하여 해결했습니다 .

function methodThatChainsPromises(args) {

    //var args = [
    //    'myArg1',
    //    'myArg2',
    //    'myArg3',
    //];

    var deferred = $q.defer();
    var chain = args.map(methodThatTakeArgAndReturnsPromise);

    $q.all(chain)
    .then(function () {
        $log.debug('All promises have been resolved.');
        deferred.resolve();
    })
    .catch(function () {
        $log.debug('One or more promises failed.');
        deferred.reject();
    });

    return deferred.promise;
}

jQuery.map ()이 아니라 Array.prototype.map () ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )이지만이 접근 방식은 작동합니다.
Anastasia


0

"async function"에서 "await"를 사용할 수 있습니다 .

app.controller('MainCtrl', async function($scope, $q, $timeout) {
  ...
  var all = await $q.all([one.promise, two.promise, three.promise]); 
  ...
}

참고 : 비 비동기 함수에서 비동기 함수를 호출하고 올바른 결과를 얻을 수 있는지 100 % 확신하지 못합니다.

그것은 이것이 웹 사이트에서 사용되지 않을 것이라고 말했습니다. 하지만 부하 테스트 / 통합 테스트의 경우 ...

예제 코드 :

async function waitForIt(printMe) {
  console.log(printMe);
  console.log("..."+await req());
  console.log("Legendary!")
}

function req() {
  
  var promise = new Promise(resolve => {
    setTimeout(() => {
      resolve("DARY!");
    }, 2000);
    
  });

    return promise;
}

waitForIt("Legen-Wait For It");

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.