두 개의 JS 함수가 있습니다. 하나는 다른 하나를 호출합니다. 호출 기능 내에서 다른 기능을 호출하고 해당 기능이 완료 될 때까지 기다렸다가 계속 진행하고 싶습니다. 예를 들어 / 의사 코드 :
function firstFunction(){
for(i=0;i<x;i++){
// do something
}
};
function secondFunction(){
firstFunction()
// now wait for firstFunction to finish...
// do something else
};
나는이 해결책을 생각해 냈지만 이것이 현명한 방법인지는 모른다.
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
합법적입니까? 그것을 처리하는 더 우아한 방법이 있습니까? 아마도 jQuery와 함께?
답변
이와 같은 비동기 작업을 처리하는 한 가지 방법은 다음과 같은 콜백 함수를 사용하는 것입니다.
function firstFunction(_callback){
// do some asynchronous work
// and when the asynchronous stuff is complete
_callback();
}
function secondFunction(){
// call first function and pass in a callback function which
// first function runs when it has completed
firstFunction(function() {
console.log('huzzah, I\'m done!');
});
}
@Janaka Pushpakumara의 제안에 따라 화살표 기능을 사용하여 동일한 것을 얻을 수 있습니다. 예를 들면 다음과 같습니다.
firstFunction(() => console.log('huzzah, I\'m done!'))
업데이트 : 나는 꽤 오래 전에 이것을 대답하고 정말로 업데이트하고 싶습니다. 콜백은 절대적으로 좋지만 내 경험상 코드를 읽고 유지하기가 더 어려운 경향이 있습니다. 진행중인 이벤트 등을 매개 변수로 전달하는 등 여전히 사용하는 상황이 있습니다. 이 업데이트는 대안을 강조하기위한 것입니다.
또한 원래의 질문은 specificallty 함수가 동기 인 경우,이 때문에 경우에 누군가가 혼란, 비동기를 언급하지 않는 것입니다 전화했을 때 차단합니다. 예를 들면 다음과 같습니다.
doSomething()
// the function below will wait until doSomething completes if it is synchronous
doSomethingElse()
암시 적으로 함수가 비동기 적이지만 오늘날 모든 비동기 작업을 처리하는 방법은 async / await입니다. 예를 들면 다음과 같습니다.
const secondFunction = async () => {
const result = await firstFunction()
// do something else here after firstFunction completes
}
IMO, async / await는 약속을 직접 사용하는 것보다 (대부분의 경우) 코드를 훨씬 더 읽기 쉽게 만듭니다. 잡기 오류를 처리해야 할 경우 try / catch와 함께 사용하십시오. 자세한 내용은 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function에서 확인하십시오 .
답변
async / await 사용 :
async function firstFunction(){
for(i=0;i<x;i++){
// do something
}
return;
};
그런 다음 다른 함수에서 await를 사용하여 반환 될 때까지 기다리십시오.
async function secondFunction(){
await firstFunction();
// now wait for firstFunction to finish...
// do something else
};
답변
여기서 중요한 점이 누락 된 것 같습니다. JavaScript는 단일 스레드 실행 환경입니다. 코드를 다시 살펴 보겠습니다 alert("Here")
.
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
alert("Here");
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
기다릴 필요가 없습니다 isPaused
. “여기”경고 isPaused
가 표시되면 false
이미 firstFunction
표시되어 반환됩니다. for
루프 ( // do something
) 내부에서 “수율”할 수 없기 때문에 루프가 중단되지 않고 먼저 완전히 완료해야합니다 (자세한 내용 : Javascript 스레드 처리 및 경쟁 조건 ).
즉, 내부에서 코드 흐름 firstFunction
을 비 동기화하고 콜백을 사용하거나 발신자에게 알리겠다고 약속 할 수 있습니다. for
루프 를 포기하고 if
대신 ( JSFiddle )로 시뮬레이션해야합니다 .
function firstFunction()
{
var deferred = $.Deferred();
var i = 0;
var nextStep = function() {
if (i<10) {
// Do something
printOutput("Step: " + i);
i++;
setTimeout(nextStep, 500);
}
else {
deferred.resolve(i);
}
}
nextStep();
return deferred.promise();
}
function secondFunction()
{
var promise = firstFunction();
promise.then(function(result) {
printOutput("Result: " + result);
});
}
참고로 JavaScript 1.7은 yield
키워드를 생성기 의 일부로 도입했습니다 . 이를 통해 동기식 JavaScript 코드 흐름에서 비동기 홀을 “펀칭”할 수 있습니다 ( 자세한 내용 및 예 ). 그러나 생성기에 대한 브라우저 지원은 현재 Firefox 및 Chrome (AFAIK)으로 제한됩니다.
답변
하나의 기능이 먼저 완료 될 때까지 기다리는 가장 좋은 방법은 비동기 / 대기 기능 과 함께 약속 을 사용하는 것입니다.
- 먼저 Promise를 만듭니다 . 내가 만든 기능은 2 초 후에 완료됩니다.
setTimeout
명령을 실행하는 데 시간이 걸리는 상황을 보여주기 위해 사용
했습니다. - 두 번째 기능의 경우 지침을 진행하기 전에 첫 번째 기능을 완료
할 비동기 / 대기 기능을 사용할 수 있습니다
await
.
예:
//1. Create a new function that returns a promise
function firstFunction() {
return new Promise((resolve, reject) => {
let y = 0
setTimeout(() => {
for(i=0; i<10; i++){
y++
}
console.log('loop completed')
resolve(y)
}, 2000)
})
}
//2. Create an async function
async function secondFunction() {
console.log('before promise call')
//3. Await for the first function to complete
let result = await firstFunction()
console.log('promise resolved: ' + result)
console.log('next step')
};
secondFunction()
노트 :
당신은 할 수 단순히 과 같이 값없이 . 내 예에서, I 의 가치와 나는 다음 두 번째 기능에서 사용할 수있다.resolve
Promise
resolve()
resolved
Promise
y
답변
약속의 유일한 문제는 IE가 약속을 지원하지 않는다는 것입니다. 에지는 않지만, IE 10의 많음이있다 11가 아웃 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise (하단에 호환성)
따라서 JavaScript는 단일 스레드입니다. 비동기 호출을하지 않으면 예상대로 작동합니다. 기본 JavaScript 스레드는 코드에 표시되는 순서대로 다음 함수를 실행하기 전에 하나의 함수를 완전히 실행합니다. 동기 함수의 순서를 보장하는 것은 쉽지 않습니다. 각 함수는 호출 된 순서대로 완전히 실행됩니다.
동기 함수를 원자 단위 작업으로 생각하십시오 . 기본 JavaScript 스레드는 명령문이 코드에 나타나는 순서대로이를 완전히 실행합니다.
그러나 다음 상황과 같이 비동기 호출을 처리하십시오.
showLoadingDiv(); // function 1
makeAjaxCall(); // function 2 - contains async ajax call
hideLoadingDiv(); // function 3
이것은 당신이 원하는 것을하지 않습니다 . 기능 1, 기능 2 및 기능 3을 즉시 실행합니다. div 플래시가로드되고 사라졌지 만 ajax 호출이 거의 완료되지는 않았지만 makeAjaxCall()
반환되었습니다. 복잡한 것은 makeAjaxCall()
주요 JavaScript 스레드의 각 스핀에 의해 조금씩 진행되는 덩어리로 작업을 나눕니다 . 비동기 적으로 작동합니다. 그러나 한 번의 스핀 / 런 동안 동일한 메인 스레드가 동기식 부분을 빠르고 예측 가능하게 실행했습니다.
그래서, 내가 그것을 다루는 방식 : 내가 말했듯이 기능은 원자 작업 단위입니다. 함수 1과 2의 코드를 결합했습니다. 비동기 호출 전에 함수 1의 코드를 함수 2에 넣습니다. 함수 1을 제거했습니다. 비동기 호출을 포함하여 모든 것을 순서대로 예측 가능하게 실행합니다.
그런 다음 비동기 호출이 완료되면 기본 JavaScript 스레드를 여러 번 회전 한 후 함수 3을 호출하게합니다 . 그러면 order가 보장됩니다 . 예를 들어, ajax를 사용하면 onreadystatechange 이벤트 핸들러가 여러 번 호출됩니다. 완료되었다고보고되면 원하는 최종 함수를 호출하십시오.
더 지저분하다는 데 동의합니다. 나는 코드가 대칭 적 인 것을 좋아하고, 함수가 한 가지 일 (또는 그에 가까운)을하는 것을 좋아하며, 어떤 식 으로든 아약스 호출이 디스플레이를 담당하는 것을 좋아하지 않습니다 (호출자에 대한 종속성 생성). 그러나 동기식 함수에 비동기 호출이 임베드 된 경우 실행 순서를 보장하려면 절충이 필요합니다. 그리고 IE 10을 코딩해야하므로 약속이 없습니다.
요약 : 동기식 호출의 경우 순서를 보장하는 것이 쉽지 않습니다. 각 함수는 호출 된 순서대로 완전히 실행됩니다. 비동기식 호출이있는 함수의 경우 순서를 보장하는 유일한 방법은 비동기식 호출이 완료되는시기를 모니터링하고 해당 상태가 감지되면 세 번째 함수를 호출하는 것입니다.
JavaScript 스레드에 대한 설명은 https://medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23 및 https://developer.mozilla.org/en-US/docs/Web/JavaScript/를 참조하십시오. EventLoop
또한이 주제에 대해 비슷한 비슷한 등급의 질문이 있습니다 .3 개의 함수를 하나씩 실행하려면 어떻게해야합니까?
답변
체인에서 여러 작업을 실행해야하기 때문에이 문제가 발생했습니다.
<button onclick="tprom('Hello Niclas')">test promise</button>
<script>
function tprom(mess) {
console.clear();
var promise = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(mess);
}, 2000);
});
var promise2 = new Promise(async function (resolve, reject) {
await promise;
setTimeout(function () {
resolve(mess + ' ' + mess);
}, 2000);
});
var promise3 = new Promise(async function (resolve, reject) {
await promise2;
setTimeout(function () {
resolve(mess + ' ' + mess+ ' ' + mess);
}, 2000);
});
promise.then(function (data) {
console.log(data);
});
promise2.then(function (data) {
console.log(data);
});
promise3.then(function (data) {
console.log(data);
});
}
</script>
답변
당신의 주요 재미는 firstFun을 호출하고 완료되면 다음 재미가 호출됩니다.
async firstFunction() {
const promise = new Promise((resolve, reject) => {
for (let i = 0; i < 5; i++) {
// do something
console.log(i);
if (i == 4) {
resolve(i);
}
}
});
const result = await promise;
}
second() {
this.firstFunction().then( res => {
// third function call do something
console.log('Gajender here');
});
}