3 개의 함수를 차례로 호출하려면 어떻게해야합니까?


151

이 함수를 하나씩 호출해야하는 경우

$('#art1').animate({'width':'1000px'},1000);        
$('#art2').animate({'width':'1000px'},1000);        
$('#art3').animate({'width':'1000px'},1000);        

jQuery에서 다음과 같은 작업을 수행 할 수 있다는 것을 알고 있습니다.

$('#art1').animate({'width':'1000px'},1000,'linear',function(){
    $('#art2').animate({'width':'1000px'},1000,'linear',function(){
        $('#art3').animate({'width':'1000px'},1000);        
    });        
});        

그러나 jQuery를 사용하지 않고 전화를 걸고 싶다고 가정 해 봅시다.

some_3secs_function(some_value);        
some_5secs_function(some_value);        
some_8secs_function(some_value);        

실행하기 위해이 함수를 호출하고 호출이 some_3secs_function끝난 후 실행 한 다음 some_5secs_function호출이 종료 된 후 호출하는 방법은 some_8secs_function무엇입니까?

최신 정보:

여전히 작동하지 않습니다.

(function(callback){
    $('#art1').animate({'width':'1000px'},1000);
    callback();
})((function(callback2){
    $('#art2').animate({'width':'1000px'},1000);
    callback2();
})(function(){
    $('#art3').animate({'width':'1000px'},1000);
}));

세 애니메이션이 동시에 시작됩니다

내 실수는 어디에?


함수가 정확히 3 5 & 8 초 또는 한 번에 하나씩 호출되어야합니까?
Trass Vasston

나는 당신이 단순히 동기 함수와 비동기 함수 실행에 대해 확신하지 못한다고 생각 합니다. 아래 답변을 업데이트했습니다. 도움이 되길 바랍니다.
Wayne

답변:


243

자바 스크립트에는 동기식비동기식 기능이 있습니다.

동기 함수

Javascript의 대부분의 함수는 동기식입니다. 여러 개의 동기 함수를 연속해서 호출하려는 경우

doSomething();
doSomethingElse();
doSomethingUsefulThisTime();

그들은 순서대로 실행됩니다. 완료 doSomethingElse될 때까지 시작되지 않습니다 doSomething. doSomethingUsefulThisTime, doSomethingElse완료 될 때까지 시작되지 않습니다 .

비동기 함수

그러나 비동기 기능은 서로를 기다리지 않습니다. 함수가 비동기라고 가정 할 때, 위와 동일한 코드 샘플을 보자.

doSomething();
doSomethingElse();
doSomethingUsefulThisTime();

기능은 순서대로 초기화되지만 모두 동시에 실행됩니다. 어느 쪽이 먼저 끝날지 일관되게 예측할 수 없습니다. 실행하는 데 가장 짧은 시간이 걸리는 쪽이 먼저 끝납니다.

그러나 때때로 비동기식 함수가 순서대로 실행되기를 원하고 동기식 함수가 비동기식으로 실행되기를 원할 수도 있습니다. 다행히 콜백 및 타임 아웃이 각각 가능합니다.

콜백

하자 우리가 순서대로 실행하려는 것을 세 비동기 기능을 가지고 있다고 가정 some_3secs_function, some_5secs_function하고 some_8secs_function.

함수는 Javascript에서 인수로 전달 될 수 있으므로 함수가 완료된 후 실행할 콜백으로 함수를 전달할 수 있습니다.

우리가 이런 함수를 만들면

function some_3secs_function(value, callback){
  //do stuff
  callback();
}

다음과 같이 순서대로 호출 할 수 있습니다.

some_3secs_function(some_value, function() {
  some_5secs_function(other_value, function() {
    some_8secs_function(third_value, function() {
      //All three functions have completed, in order.
    });
  });
});

타임 아웃

Javascript에서는 특정 시간 초과 (밀리 초) 후에 함수가 실행되도록 지시 할 수 있습니다. 결과적으로 동기 함수가 비동기 적으로 동작하게 할 수 있습니다.

세 개의 동기 함수가있는 경우 함수를 사용하여 비동기 적으로 실행할 수 setTimeout있습니다.

setTimeout(doSomething, 10);
setTimeout(doSomethingElse, 10);
setTimeout(doSomethingUsefulThisTime, 10);

그러나 이것은 약간 추악하며 DRY 원칙 [wikipedia]을 위반합니다 . 함수 배열과 타임 아웃을 받아들이는 함수를 만들어서 약간 정리할 수 있습니다.

function executeAsynchronously(functions, timeout) {
  for(var i = 0; i < functions.length; i++) {
    setTimeout(functions[i], timeout);
  }
}

다음과 같이 호출 할 수 있습니다.

executeAsynchronously(
    [doSomething, doSomethingElse, doSomethingUsefulThisTime], 10);

요약하면, 비동기식으로 실행하려는 비동기 함수가있는 경우 콜백을 사용하고 비동기식으로 실행하려는 동기 함수가있는 경우 시간 종료를 사용하십시오.


7
이 예제에서 제안한대로 3,5 및 8 초 동안 기능이 지연되지는 않습니다.
Trass Vasston

1
@ 피터-잠깐, 그래서 혼란 스러워요. 이것이 완료하는 데 몇 초가 걸리는 간단한 동기식 호출 인 경우 왜이 중 하나가 필요한가요?
Wayne

9
@Peter-세 가지 동기 함수를 순서대로 호출하는 데 본 가장 아름답고 복잡한 방법은 +1입니다.
Wayne

4
비동기 및 동기화 js 기능의 차이점을 전문적으로 설명해 주셔서 감사합니다. 이것은 너무 많은 설명입니다.
jnelson

2
이것은 다음과 같은 이유로 정확 하지 않습니다 . (1) 3 개의 타임 아웃이 10 초 후에 모두 해결되므로 3 개의 라인이 동시에 트리거됩니다. (2)이 방법을 사용하려면 체인의 이전 비동기 함수가 해결되고 트리거되는 것을 기다리지 말고 미리 지속 시간과 "일정"기능을 알아야합니다. --- 대신 콜백, 약속 또는 비동기 라이브러리를 사용하여 다음 응답 중 하나를 사용하려고합니다.
zeroasterisk

37

이 답변은 표준 promises의 JavaScript 기능인을 사용합니다 ECMAScript 6. 대상 플랫폼이 지원하지 않으면 promisesPromiseJs로 폴리 필하십시오 .

내 대답은 여기를보십시오 . 애니메이션 을 사용하려면 다른 함수를 실행할 때까지 애니메이션이있는 함수가 끝날 때까지 기다리 십시오 jQuery.

다음은 코드의 모양이 ES6 PromisesjQuery animations입니다.

Promise.resolve($('#art1').animate({ 'width': '1000px' }, 1000).promise()).then(function(){
    return Promise.resolve($('#art2').animate({ 'width': '1000px' }, 1000).promise());
}).then(function(){
    return Promise.resolve($('#art3').animate({ 'width': '1000px' }, 1000).promise());
});

일반 메소드도 래핑 할 수 있습니다 Promises.

new Promise(function(fulfill, reject){
    //do something for 5 seconds
    fulfill(result);
}).then(function(result){
    return new Promise(function(fulfill, reject){
        //do something for 5 seconds
        fulfill(result);
    });
}).then(function(result){
    return new Promise(function(fulfill, reject){
        //do something for 8 seconds
        fulfill(result);
    });
}).then(function(result){
    //do something with the result
});

then방법은 곧만큼 실행 Promise완료. 일반적으로 function전달 된 대상 의 반환 값은 다음 값으로 전달됩니다 then.

그러나 a Promise가 반환되면 다음 then함수는 Promise실행 이 끝날 때까지 기다렸다가 그 결과 (에 전달되는 값 fulfill)를받습니다.


이것이 유용하다는 것을 알고 있지만 실제 예제를 찾지 않고 이해하기 어려운 코드를 찾았습니다. : 나는 YouTube에서이 비디오를 발견 youtube.com/watch?v=y5mltEaQxa0을 여기에 비디오에서 소스를 쓴 - drive.google.com/file/d/1NrsAYs1oaxXw0kv9hz7a6LjtOEb6x7z-/... 캐치가 누락과 같은 좀 더 미묘한 차이가 있습니다 이 예는 이에 대해 자세히 설명합니다. (getPostById () 행에 다른 ID를 사용하거나 작성자 이름을 변경하여 게시물과 일치하지 않도록하십시오)
JGFMK

20

동기 함수 와 비동기 함수 실행 의 차이를 완전히 인식하지 못하는 것 같습니다 .

업데이트에서 제공 한 코드는 각 콜백 함수를 즉시 실행하여 애니메이션을 즉시 시작합니다. 그러나 애니메이션은 비동기 적으로 실행 됩니다. 다음과 같이 작동합니다.

  1. 애니메이션에서 단계 수행
  2. setTimeout다음 애니메이션 단계와 지연을 포함하는 함수로 호출
  3. 시간이 지남
  4. 주어진 콜백 setTimeout이 실행
  5. 1 단계로 돌아가십시오

이것은 애니메이션의 마지막 단계가 완료 될 때까지 계속됩니다. 그 동안 동기 기능이 오래 전에 완료되었습니다. 즉, animate함수 호출에 실제로 3 초가 걸리지 않습니다 . 지연 및 콜백으로 효과가 시뮬레이션됩니다.

필요한 것은 대기열 입니다. 내부적으로 jQuery는 애니메이션을 큐에 넣고 해당 애니메이션이 완료된 후에 만 콜백을 실행 합니다 . 콜백이 다른 애니메이션을 시작하면 효과가 순서대로 실행됩니다.

가장 간단한 경우 이것은 다음과 같습니다.

window.setTimeout(function() {
    alert("!");
    // set another timeout once the first completes
    window.setTimeout(function() {
        alert("!!");
    }, 1000);
}, 3000); // longer, but first

일반적인 비동기 루핑 기능은 다음과 같습니다. 주어진 함수를 순서대로 호출하고 각 함수 사이에 지정된 시간 (초) 동안 기다립니다.

function loop() {
    var args = arguments;
    if (args.length <= 0)
        return;
    (function chain(i) {
        if (i >= args.length || typeof args[i] !== 'function')
            return;
        window.setTimeout(function() {
            args[i]();
            chain(i + 1);
        }, 2000);
    })(0);
}    

용법:

loop(
  function() { alert("sam"); }, 
  function() { alert("sue"); });

구성 가능한 대기 시간이 걸리거나 즉시 첫 번째 기능을 실행 false하거나 체인 apply의 기능이 반환 되거나 지정된 컨텍스트의 기능 또는 기타 필요한 기능이 실행될 때 실행을 중지하도록 분명히 수정할 수 있습니다.


14

비동기 라이브러리가이를 수행하는 매우 우아한 방법을 제공 할 것이라고 생각합니다 . 약속과 콜백은 다루기가 약간 어려워 질 수 있지만 비동기는 깔끔한 패턴으로 생각 프로세스를 간소화 할 수 있습니다. 직렬로 함수를 실행하려면 비동기 폭포수 에 넣어야합니다 . 비동기 링고에서 모든 함수는 task일부 인수를 취하는 a라고 하며 callback; 시퀀스에서 다음 함수입니다. 기본 구조는 다음과 같습니다.

async.waterfall([
  // A list of functions
  function(callback){
      // Function no. 1 in sequence
      callback(null, arg);
  },
  function(arg, callback){
      // Function no. 2 in sequence
      callback(null);
  }
],    
function(err, results){
   // Optional final callback will get results for all prior functions
});

방금 구조를 간단히 설명하려고했습니다. 자세한 내용 은 워터 폴 가이드 를 참조하십시오.


1
이것은 실제로 JS를 좀 더 견딜 수있게 만듭니다.
mike

9

함수는 콜백 함수를 가져와야 할 때 호출됩니다.

function fone(callback){
...do something...
callback.apply(this,[]);

}

function ftwo(callback){
...do something...
callback.apply(this,[]);
}

다음 사용법은 다음과 같습니다.

fone(function(){
  ftwo(function(){
   ..ftwo done...
  })
});

4
asec=1000; 

setTimeout('some_3secs_function("somevalue")',asec*3);
setTimeout('some_5secs_function("somevalue")',asec*5);
setTimeout('some_8secs_function("somevalue")',asec*8);

여기서는 setTimeout에 대해 자세히 설명하지 않겠습니다.

  • 이 경우 문자열로 실행할 코드를 추가했습니다. 이것은 var를 setTimeout-ed 함수에 전달하는 가장 간단한 방법이지만 순수 주의자가 불평합니다.
  • 따옴표없이 함수 이름을 전달할 수도 있지만 변수는 전달할 수 없습니다.
  • 코드는 setTimeout이 트리거 될 때까지 기다리지 않습니다.
  • 이것은 처음에 머리를 돌리기 어려울 수 있습니다. 이전 시점 때문에 호출 함수에서 변수를 전달하면 시간 초과가 트리거 될 때까지 해당 변수가 더 이상 존재하지 않습니다. 호출 함수가 실행되어 vars gone.
  • 익명의 함수를 사용하여이 문제를 해결하는 것으로 알려져 있지만 더 나은 방법이있을 수 있습니다.

3

자바 스크립트로 태그를 지정 했으므로 함수 이름이 3, 5 및 8 초이므로 타이머 컨트롤을 사용합니다. 따라서 타이머를 3 초 동안 시작한 다음 첫 번째 전화를 걸고 5 초를 두 번째 전화를 걸고 8 초를 세 번째 전화를 걸고 타이머가 끝나면 타이머를 중지하십시오.

일반적으로 Javascript에서는 함수가 하나씩 실행되는 것이 정확하지만 시간이 초과 된 애니메이션을하려고하는 것처럼 보이기 때문에 타이머가 가장 좋습니다.


2

//sample01
(function(_){_[0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this[1].bind(this))},
	function(){$('#art2').animate({'width':'10px'},100,this[2].bind(this))},
	function(){$('#art3').animate({'width':'10px'},100)},
])

//sample02
(function(_){_.next=function(){_[++_.i].apply(_,arguments)},_[_.i=0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this.next)},
	function(){$('#art2').animate({'width':'10px'},100,this.next)},
	function(){$('#art3').animate({'width':'10px'},100)},
]);

//sample03
(function(_){_.next=function(){return _[++_.i].bind(_)},_[_.i=0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this.next())},
	function(){$('#art2').animate({'width':'10px'},100,this.next())},
	function(){$('#art3').animate({'width':'10px'},100)},
]);


이것이 무엇인지 설명해 주시겠습니까? 밑줄은 무엇입니까? 할당 된 기능은 무엇입니까 next?
mtso

1
jsfiddle을 사용하여 샘플 2를 설명합니다. jsfiddle.net/mzsteyuy/3 대략적인 설명을 허용하면 샘플 2는 jsfiddle의 간단한 코드 방법입니다. 밑줄은 대응 가능한 요소 (i)이고 다음 함수와 함수 [0] ~ [2] 인 배열입니다.
yuuya

1

이런 식으로 약속을 사용할 수도 있습니다.

    some_3secs_function(this.some_value).then(function(){
       some_5secs_function(this.some_other_value).then(function(){
          some_8secs_function(this.some_other_other_value);
       });
    });

당신은 할 것이다 some_value그 때는 내부에서 액세스 그것을 위해 글로벌

또는 외부 함수에서 내부 함수가 사용할 값을 다음과 같이 반환 할 수 있습니다.

    one(some_value).then(function(return_of_one){
       two(return_of_one).then(function(return_of_two){
          three(return_of_two);
       });
    });

0

자바 스크립트의 setTimeout을 기반으로 'waitUntil'함수를 사용합니다.

/*
    funcCond : function to call to check whether a condition is true
    readyAction : function to call when the condition was true
    checkInterval : interval to poll <optional>
    timeout : timeout until the setTimeout should stop polling (not 100% accurate. It was accurate enough for my code, but if you need exact milliseconds, please refrain from using Date <optional>
    timeoutfunc : function to call on timeout <optional>
*/
function waitUntil(funcCond, readyAction, checkInterval, timeout, timeoutfunc) {
    if (checkInterval == null) {
        checkInterval = 100; // checkinterval of 100ms by default
    }
    var start = +new Date(); // use the + to convert it to a number immediatly
    if (timeout == null) {
        timeout = Number.POSITIVE_INFINITY; // no timeout by default
    }
    var checkFunc = function() {
        var end = +new Date(); // rough timeout estimations by default

        if (end-start > timeout) {
            if (timeoutfunc){ // if timeout function was defined
                timeoutfunc(); // call timeout function
            }
        } else {
            if(funcCond()) { // if condition was met
                readyAction(); // perform ready action function
            } else {
                setTimeout(checkFunc, checkInterval); // else re-iterate
            }
        }
    };
    checkFunc(); // start check function initially
};

함수가 특정 조건을 true로 설정하면 폴링 할 수 있으면 완벽하게 작동합니다. 또한 타임 아웃이 제공되어 기능이 무언가를 수행하지 못한 경우 (시간 범위 내에서도 사용자 피드백에 대해 생각하십시오!)

예 :

doSomething();
waitUntil(function() { return doSomething_value===1;}, doSomethingElse);
waitUntil(function() { return doSomethingElse_value===1;}, doSomethingUseful);

노트

날짜는 대략적인 시간 종료 추정을 유발합니다. 정확성을 높이려면 console.time ()과 같은 기능으로 전환하십시오. Date는 브라우저 간 및 레거시 지원을 향상시킵니다. 정확한 밀리 초 측정이 필요하지 않은 경우 브라우저를 지원할 때 귀찮게하거나 대안으로 사용하지 말고 console.time ()을 제공하십시오.


0

방법 1, 방법 2, 3, 4 이후에 방법 1을 실행해야하는 경우 다음 코드 스 니펫은 JavaScript에서 Deferred 객체를 사용하여이를위한 솔루션이 될 수 있습니다.

function method1(){
  var dfd = new $.Deferred();
     setTimeout(function(){
     console.log("Inside Method - 1"); 
     method2(dfd);	 
    }, 5000);
  return dfd.promise();
}

function method2(dfd){
  setTimeout(function(){
   console.log("Inside Method - 2"); 
   method3(dfd);	
  }, 3000);
}

function method3(dfd){
  setTimeout(function(){
   console.log("Inside Method - 3"); 	
   dfd.resolve();
  }, 3000);
}

function method4(){   
   console.log("Inside Method - 4"); 	
}

var call = method1();

$.when(call).then(function(cb){
  method4();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

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