단위 테스트를하고 있습니다. 테스트 프레임 워크는 페이지를 iFrame에로드 한 다음 해당 페이지에 대해 어설 션을 실행합니다. 각 테스트가 시작되기 전에 를 호출 Promise
할 iFrame의 onload
이벤트를 resolve()
설정하고 iFrame의을 설정 src
하고 promise를 반환 하는를 만듭니다.
따라서을 호출 loadUrl(url).then(myFunc)
하면 무엇이든지 실행하기 전에 페이지가로드 될 때까지 기다립니다 myFunc
.
주로 DOM 변경을 허용하기 위해 (예 : 버튼 클릭을 흉내 내고 div가 숨기고 표시 될 때까지 기다릴 때까지) 내 테스트 (URL로드뿐만 아니라) 전체에서 이런 종류의 패턴을 사용합니다.
이 디자인의 단점은 몇 줄의 코드로 익명 함수를 계속 작성하고 있다는 것입니다. 또한 해결 방법 (QUnit assert.async()
)이 있지만 약속을 정의하는 테스트 함수는 약속이 실행되기 전에 완료됩니다.
Promise
.NET의 .NET과 유사하게 해결 될 때까지 또는 대기 (블록 / 슬립) 에서 값을 가져 오는 방법이 있는지 궁금합니다 IAsyncResult.WaitHandle.WaitOne()
. JavaScript가 단일 스레드라는 것을 알고 있지만 이것이 함수가 양보 할 수 없다는 것을 의미하지는 않기를 바랍니다.
본질적으로 올바른 순서로 결과를 뱉어 내기 위해 다음을 얻을 수있는 방법이 있습니까?
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
};
function getResultFrom(promise) {
// todo
return " end";
}
var promise = kickOff();
var result = getResultFrom(promise);
$("#output").append(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
답변
.NET의 IAsyncResult.WaitHandle.WaitOne ()과 유사하게 Promise에서 값을 가져 오거나 해결 될 때까지 대기 (차단 / 절전) 할 수있는 방법이 있는지 궁금합니다. 자바 스크립트가 단일 스레드라는 것을 알고 있지만 이것이 함수가 양보 할 수 없다는 것을 의미하지는 않기를 바랍니다.
브라우저에서 자바 스크립트의 현재 세대는없는 wait()
또는 sleep()
그 실행에 다른 일을 할 수 있습니다. 그래서 당신은 단순히 당신이 요구하는 것을 할 수 없습니다. 대신, 작업을 수행 한 다음 완료되면 호출하는 비동기 작업이 있습니다 (Promise를 사용했던 것처럼).
이것의 일부는 Javascript의 단일 스레드 성 때문입니다. 단일 스레드가 회전 중이면 해당 회전 스레드가 완료 될 때까지 다른 Javascript를 실행할 수 없습니다. ES6는 yield
이와 같은 협력적인 트릭을 허용하는 생성기를 도입 했지만, 설치된 브라우저의 광범위한 견본에서 사용할 수있는 방법은 상당히 많습니다 (JS 엔진을 제어하는 서버 측 개발에서 사용할 수 있습니다) 사용중인).
약속 기반 코드를주의 깊게 관리하면 많은 비동기 작업의 실행 순서를 제어 할 수 있습니다.
코드에서 달성하려는 순서를 정확히 이해하지 못했지만 기존 kickOff()
함수를 사용하여 이와 같은 작업을 수행 한 다음 .then()
호출 한 후 처리기를 연결할 수 있습니다.
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
}
kickOff().then(function(result) {
// use the result here
$("#output").append(result);
});
다음과 같이 보증 된 순서로 출력을 반환합니다.
start
middle
end
2018 년 업데이트 (이 답변이 작성된 후 3 년) :
당신도 당신의 코드를 transpile 또는 지원 ES7 같은 기능을한다는 환경에서 코드를 실행하는 경우 async
와 await
, 당신은 지금 사용할 수있는 await
코드가 “표시”할 약속의 결과를 기다려야한다. 그것은 여전히 약속을 가지고 발전하고 있습니다. 여전히 모든 Javascript를 차단하지는 않지만 더 친숙한 구문으로 순차적 작업을 작성할 수 있습니다.
ES6 방식 대신 :
someFunc().then(someFunc2).then(result => {
// process result here
}).catch(err => {
// process error here
});
다음과 같이 할 수 있습니다.
// returns a promise
async function wrapperFunc() {
try {
let r1 = await someFunc();
let r2 = await someFunc2(r1);
// now process r2
return someValue; // this will be the resolved value of the returned promise
} catch(e) {
console.log(e);
throw e; // let caller know the promise was rejected with this reason
}
}
wrapperFunc().then(result => {
// got final result
}).catch(err => {
// got error
});
답변
ES2016을 사용하는 경우 사용할 수 있습니다 async
및 await
과 같은 것을 할 :
(async () => {
const data = await fetch(url)
myFunc(data)
}())
ES2015를 사용하는 경우 Generators 를 사용할 수 있습니다 . 구문이 마음에 들지 않으면 여기에 설명 된 대로 async
유틸리티 함수 를 사용하여 추상화 할 수 있습니다 .
ES5를 사용하는 경우 Bluebird 와 같은 라이브러리가 더 많은 제어를 제공하기를 원할 것입니다 .
마지막으로 런타임이 ES2015를 지원하는 경우 이미 실행 순서는 Fetch Injection을 사용하여 병렬 처리로 보존 될 수 있습니다 .
답변
또 다른 옵션은 Promise.all을 사용하여 일련의 프라 미스가 해결 될 때까지 기다리는 것입니다. 아래 코드는 모든 약속이 해결 될 때까지 기다린 다음 모든 준비가 완료되면 결과를 처리하는 방법을 보여줍니다 (질문의 목적인 것처럼 보임). 그러나 start는 resolve를 호출하기 전에 해당 코드를 추가하는 것만으로 middle이 해결되기 전에 분명히 출력 할 수 있습니다.
function kickOff() {
let start = new Promise((resolve, reject) => resolve("start"))
let middle = new Promise((resolve, reject) => {
setTimeout(() => resolve(" middle"), 1000)
})
let end = new Promise((resolve, reject) => resolve(" end"))
Promise.all([start, middle, end]).then(results => {
results.forEach(result => $("#output").append(result))
})
}
kickOff()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
답변
수동으로 할 수 있습니다. (그게 좋은 해결책은 아니지만 ..) 값이 없을 while
때까지 루프를 사용하십시오.result
kickOff().then(function(result) {
while(true){
if (result === undefined) continue;
else {
$("#output").append(result);
return;
}
}
});