함수를 다시 시작하기 전에 JavaScript Promise가 해결되기를 기다리는 방법은 무엇입니까?
단위 테스트를하고 있습니다. 테스트 프레임 워크는 페이지를 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에서 값을 가져 오거나 해결 될 때까지 대기 (차단 / 절전) 할 수있는 방법이 있는지 궁금합니다. JavaScript가 단일 스레드라는 것을 알고 있지만 이것이 함수가 양보 할 수 없다는 것을 의미하지는 않기를 바랍니다.
브라우저에서 자바 스크립트의 현재 세대는없는 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 년) :
코드를 트랜스 파일하거나 async
및과 같은 ES7 기능을 지원하는 환경에서 코드를 실행하는 경우 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)
}())
If using ES2015 you can use Generators. If you don't like the syntax you can abstract it away using an async
utility function as explained here.
If using ES5 you'll probably want a library like Bluebird to give you more control.
Finally, if your runtime supports ES2015 already execution order may be preserved with parallelism using Fetch Injection.
Another option is to use Promise.all to wait for an array of promises to resolve. Code below shows how to wait for all the promises to resolve and then deal with the results once they are all ready (as that seemed to be the objective of the question); However, start could obviously output before middle has resolved just by adding that code before it calls resolve.
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>
You can do it manually. (I know, that that isn't great solution, but..) use while
loop till the result
hasn't a value
kickOff().then(function(result) {
while(true){
if (result === undefined) continue;
else {
$("#output").append(result);
return;
}
}
});
'Program Tip' 카테고리의 다른 글
2011/2012의 Java JDBC 연결 풀 라이브러리 선택? (0) | 2020.10.30 |
---|---|
Rust의 옵션 유형의 오버 헤드는 무엇입니까? (0) | 2020.10.30 |
const에 대한 rvalue 참조가 사용됩니까? (0) | 2020.10.30 |
지도가 Python 3에서 목록 대신지도 객체를 반환하는 이유는 무엇입니까? (0) | 2020.10.30 |
log4j가 자체 구성에 사용한 파일을 표시하도록 할 수 있습니까? (0) | 2020.10.30 |