2017-11-15 13 views
0

지연/약속에 문제가 있습니다. 나는 순차적으로 실행되어야하는 두 개의 함수를 호출하는 주요 함수를 가지고있다. 첫 번째는 직렬로 먼저 실행해야하는 일련의 비동기 웹 서비스 호출을 포함합니다. 하지만 실제로 두 번째 함수는 첫 번째 함수에서 모든 비동기 피드백이 오기 전에 호출됩니다. https://fiddle.jshell.net/qLf1c0uq/ 여기jQuery deferred : 메소드에서 중첩 약속, 너무 늦은 마지막 콜백

는 참조 코드입니다 :

나는 내 문제를 보여주는 작은 예를 건설하는 세 번째 기능이 종료하기 전에 GroupFunction2가 시작

function first() { 
 
    $('ul').append("<li>first started</li>"); 
 
    let deferred = $.Deferred(); 
 
    setTimeout(function() { // Any async function. 
 
    $('ul').append("<li>first ended</li>"); 
 
    deferred.resolve(); 
 
    }, 2000); 
 
    return deferred.promise(); 
 
} 
 

 
function second(da) { 
 
    $('ul').append("<li>second started</li>"); 
 
    let deferred = $.Deferred(); 
 
    $('ul').append("<li>second ended</li>"); 
 
    deferred.resolve(); 
 
    return deferred.promise(); 
 
} 
 

 
function third(da) { 
 
    $('ul').append('<li>third started</li>') 
 
    let deferred = $.Deferred(); 
 
    setTimeout(function() { 
 
    $('ul').append("<li>third ended</li>"); 
 
    deferred.resolve(); 
 
    }, 2000); 
 

 
    return deferred.promise(); 
 
} 
 

 
function GroupFunction1() { 
 
    let deferred = $.Deferred(); 
 
    $('ul').append("<li>Group 1 started</li>"); 
 
    var data = "test2"; 
 
    $.when(first()).then(function() { 
 
    second(data); 
 
    }).then(function() { 
 
    third("test2"); 
 
    }).then(function() { 
 
    $('ul').append("<li>Group 1 ended</li>"); 
 
    deferred.resolve(); 
 
    }); 
 

 
    return deferred.promise(); 
 
} 
 

 
function GroupFunction2() { 
 
    $('ul').append("<li>Group 2 started</li>"); 
 

 
    $('ul').append("<li>Group 2 ended</li>"); 
 
} 
 

 
$(function() { 
 
    $.when(GroupFunction1()).then(GroupFunction2); 
 
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<ul></ul>
. 나는 그 반대의 경우를 기대하고있었습니다.

누구든지 도움을받을 수 있습니까?

감사합니다.

답변

1

콜백 함수 내에있는 약속은 return입니다. 이것이 약속의 사슬이 그들을 기다릴 수있는 유일한 방법입니다.

또한 Explicit Promise Creation Antipattern을 악용하는 것입니다.

.then()는 약속을 반환합니다. 너는 그걸 돌려 줄 수있어. 그리고 모든 $.when() 할 것입니다 때문에 $.when()로 한 약속을 통과에는 점은 바로 철회 침됩니다 없다 :

function first() { 
 
    $('ul').append("<li>first started</li>"); 
 
    let deferred = $.Deferred(); 
 
    setTimeout(function() { // Any async function. 
 
    $('ul').append("<li>first ended</li>"); 
 
    deferred.resolve(); 
 
    }, 2000); 
 
    return deferred.promise(); 
 
} 
 

 
function second(da) { 
 
    $('ul').append("<li>second started</li>"); 
 
    let deferred = $.Deferred(); 
 
    $('ul').append("<li>second ended</li>"); 
 
    deferred.resolve(); 
 
    return deferred.promise(); 
 
} 
 

 
function third(da) { 
 
    $('ul').append('<li>third started</li>') 
 
    let deferred = $.Deferred(); 
 
    setTimeout(function() { 
 
    $('ul').append("<li>third ended</li>"); 
 
    deferred.resolve(); 
 
    }, 2000); 
 

 
    return deferred.promise(); 
 
} 
 

 
function GroupFunction1() { 
 
    let deferred = $.Deferred(); 
 
    $('ul').append("<li>Group 1 started</li>"); 
 
    var data = "test2"; 
 

 
    // v-- here 
 
    return first()  // v-- here 
 
    .then(function() { return second(data); }) 
 
    .then(function() { return third("test2"); }) 
 
    .then(function() { $('ul').append("<li>Group 1 ended</li>"); }); 
 
} 
 

 
function GroupFunction2() { 
 
    $('ul').append("<li>Group 2 started</li>"); 
 

 
    $('ul').append("<li>Group 2 ended</li>"); 
 
} 
 

 
$(function() { 
 
    GroupFunction1().then(GroupFunction2); 
 
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<ul></ul>
정말

+0

OK, 나는) 다음 (에 귀하의 의견을 이해하지만, 나는 당신의 첫 번째 단락을하지 않았다 : 어떻게에서는 setTimeout의 콜백 함수의 약속을 반환? "return deferred.promise()"를 비동기 호출의 끝으로 이동하는 것은 나에게 의미가 없습니까?! 죄송합니다 ... –

+0

@UweGrohne 'setTimeout'의 콜백에서 반환 할 필요가 없습니다. '.then()'의 콜백으로 리턴해야합니다. 'GroupFunction1' 함수에 대한 변경 사항을보십시오. 내 대답의 코드에는 내가 언급 한 모든 수정 사항이 있습니다. – JLRishe

0

하지 질문에 대한 답변; JLRishe는 귀하의 코드가 귀하의 약속을 기다리지 않은 이유를 이미 설명했습니다.

이것은 정리 작업이며 setTimeout을 Promise로 래핑하는 약간의 유틸리티를 포함 시켰습니다. 그래서 당신은 그것을 maunally 할 필요가 없으며 모든 곳에서 반복하지 않아도됩니다.

function first(data) { 
 
    $('ul').append("<li>first started</li>"); 
 
    return wait(2000) 
 
    .then(function(){ 
 
     $('ul').append("<li>first ended</li>"); 
 
    }); 
 
} 
 

 
function second(data) { 
 
    $('ul').append("<li>second started</li>"); 
 
    $('ul').append("<li>second ended</li>"); 
 
    //let's stay consistent with our API 
 
    //even if we have to return an empty/pointless Promise for that 
 
    return Promise.resolve(); 
 
} 
 

 
function third(data) { 
 
    $('ul').append("<li>third started</li>"); 
 
    return wait(2000) 
 
    .then(function(){ 
 
     $('ul').append("<li>third ended</li>"); 
 
    }); 
 
} 
 

 

 
function GroupFunction1() { 
 
    $('ul').append("<li>Group 1 started</li>"); 
 
    var data = "test2"; 
 
    return first(data) 
 
    //.then(wait(1000)) //maybe a little pause in between? 
 
    .then(function(){ 
 
     return second(data); 
 
    }) 
 
    //.then(wait(1000)) //maybe a little pause in between? 
 
    .then(function(){ 
 
     return third(data); 
 
    }) 
 
    .then(function() { 
 
     $('ul').append("<li>Group 1 ended</li>"); 
 
    }); 
 
} 
 

 
function GroupFunction2() { 
 
    $('ul').append("<li>Group 2 started</li>"); 
 

 
    $('ul').append("<li>Group 2 ended</li>"); 
 
    return Promise.resolve(); //again, just staying consistent 
 
} 
 

 
//DRY. Get rid of all the manual setTiemouts and the Deferreds and wrap them into a function: 
 

 
//Examples on how to use: 
 
//promise = somePromise.then(wait(1000)).then(someFn); 
 
//promise = wait(1000).then(someFn); 
 
//promise = wait(1000).resolve(42); 
 
//promise = wait(30000).reject("timeout"); 
 
const wait = (function(){ 
 
\t const reject = Promise.reject.bind(Promise); 
 
\t const methods = { 
 
\t \t then(a,b){ return this().then(a,b) }, 
 
\t \t resolve(value){ return this(value) }, 
 
\t \t reject(err){ return this(err).then(reject) } 
 
\t }; 
 
\t return delay => Object.assign(value => new Promise(resolve => void setTimeout(resolve, delay, value)), methods); 
 
})(); 
 

 
$(function() { 
 
    GroupFunction1().then(GroupFunction2); 
 
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<ul></ul>