programing

기능을 재개하기 전에 자바스크립트 약속이 해결될 때까지 기다리는 방법?

javamemo 2023. 10. 7. 09:06
반응형

기능을 재개하기 전에 자바스크립트 약속이 해결될 때까지 기다리는 방법?

유닛 테스트를 하고 있습니다.테스트 프레임워크는 페이지를 iFrame에 로드한 다음 해당 페이지에 대한 주장을 실행합니다.각각의 테스트가 시작되기 전에, 나는 다음을 만듭니다.PromiseiFrame합니다를 합니다.onloadresolve() iFrame 합니다 합니다.src 거죠,.

그래서 그냥 전화하면 돼요.loadUrl(url).then(myFunc) 합니다.myFunc입니다.

테스트에서 이러한 패턴을 사용합니다(URL 로드용이 아닌). 주로 DOM에 대한 변경이 발생할 수 있도록 하기 위해(예: 버튼을 클릭하는 흉내, div가 숨어서 표시될 때까지 기다립니다)

이 디자인의 단점은 몇 줄의 코드가 들어간 익명 함수를 계속 쓰고 있다는 것입니다.제가 한,안(QUNIT의assert.async()됩니다.), 됩니다.

에서 수 이 있는지 Promise또는 와 유사하게 해결될 때까지 기다립니다(차단/절전). NETIAsyncResult.WaitHandle.WaitOne()라는 것은 가 양보할 수 은 아니길 자바스크립트가 싱글스레드라는 것은 알지만, 그렇다고 해서 함수가 양보할 수 없는 것은 아니길 바랍니다.

본질적으로, 다음과 같은 결과를 정확한 순서로 뱉어낼 수 있는 방법이 있습니까?

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의 IsyncResult.잠깐만 핸들.Wait One().자바스크립트가 싱글스레드라는 것은 알지만, 그렇다고 해서 함수가 양보할 수 없는 것은 아니길 바랍니다.

에는 가 .wait()아니면sleep()다른 것들을 실행할 수 있게 해주는 거 을 할 수 그래서, 당신은 당신이 요구하는 것을 할 수 없습니다.대신, 비동기식 운영을 통해 자신의 일을 수행하고 약속을 이행한 후 사용자에게 전화를 걸게 됩니다(사용자가 약속을 사용해 왔던 것처럼 말이죠.

이 중 일부는 자바스크립트의 단일 쓰레드성 때문입니다.만약 단일 스레드가 회전하고 있다면, 그 회전 스레드가 끝날 때까지 다른 자바스크립트를 실행할 수 없습니다., 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년 후):

ES7과 같은 async그리고.await, 이제 사용할 수 있습니다.await약속의 결과를 기다리기 위해 코드를 "appear"로 만듭니다.그것은 여전히 약속이 있는 프로그래밍을 하고 있습니다.여전히 모든 자바스크립트를 차단하지는 않지만, 보다 친근한 구문으로 순차적인 작업을 작성할 수 있습니다.

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
});

async은 첫번째합니다.await호출자에게 비동기 기능은 여전히 blocking이 아니며 호출자는 반환된 약속을 처리하고 해당 약속의 결과를 얻어야 합니다.에서,에서.async수,다를 하여 더 할 수 .await약속에 따라명심하세요.await입니다를 을 합니다. 사용하기 위해서.async/await은 모두 .

ES2016을 할 수 .async그리고.await다음과 같은 작업을 수행합니다.

(async () => {
  const data = await fetch(url)
  myFunc(data)
}())

ES2015를 사용하는 경우 제너레이터를 사용할 수 있습니다.구문이 마음에 들지 않으면 여기서 설명유틸리티 함수를 사용하여 구문을 추상화할 수 있습니다.

ES5를 사용하는 경우 Bluebird와 같은 라이브러리를 사용하여 보다 많은 제어 기능을 제공하고자 할 것입니다.

마지막으로 런타임에서 ES2015를 지원하는 경우 Fetch Injection을 사용하여 병렬로 실행 순서를 보존할 수 있습니다.

다른 옵션은 Promise를 사용하는 것입니다.모두가 약속들이 해결되기를 기다렸다가 그 약속들에 따라 행동하기 위해서입니다.

아래 코드는 모든 약속이 해결될 때까지 기다렸다가 모든 약속이 준비되면 결과를 처리하는 방법을 보여줍니다(질문의 목적인 것처럼 보였으므로).또한 예시적인 목적으로 실행 중 출력을 표시합니다(중간 전에 종료).

function append_output(suffix, value) {
  $("#output_"+suffix).append(value)
}

function kickOff() {
  let start = new Promise((resolve, reject) => {
    append_output("now", "start")
    resolve("start")
  })
  let middle = new Promise((resolve, reject) => {
    setTimeout(() => {
      append_output("now", " middle")
      resolve(" middle")
    }, 1000)
  })
  let end = new Promise((resolve, reject) => {
    append_output("now", " end")
    resolve(" end")
  })

  Promise.all([start, middle, end]).then(results => {
    results.forEach(
      result => append_output("later", result))
  })
}

kickOff()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Updated during execution: <div id="output_now"></div>
Updated after all have completed: <div id="output_later"></div>

저는 이벤트 방식으로 비동기/비동기 콜백 의존성을 다루기 위해 작은 래퍼/커널을 만들었습니다(그리고 제가 이해하기에는 매우 흥미로웠습니다).

후드 아래에서 커널은 작지만 이해하기 쉽지 않은 Promise chaining 논리를 수행합니다.

마스크된 약속 체인을 따라 적용 컨텍스트를 전달하는 데 사용할 수 있는 이벤트 개체를 만듭니다.

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// your start
qk.addEventListener('my_kickoff_event', async (e) => {
    $("#output").append("start");
    await timeout(1000);
}, 'start');

// your middle
qk.addEventListener('my_kickoff_event', (e) => {
    $("#output").append(" middle");
}, 'middle', 'start'); // <<< dependency: middle needs start

// kickoff and end
qk.dispatchEvent(new QKE('my_kickoff_event')).then((e) => {
   // it's still only Promise in the end
   $("#output").append(" end");
});
// or await qk.dispatchEvent(new QKE('my_kickoff_event'));

성능 측면에서 최적의 솔루션이 아니라 약속 변수를 쉽게 공유할 수 없는 구성 요소가 많은 일반적인 앱에서 쉽게 사용할 수 있도록 했습니다.

여기서 더

라이브 스니펫을 시도합니다.

언급URL : https://stackoverflow.com/questions/28921127/how-to-wait-for-a-javascript-promise-to-resolve-before-resuming-function

반응형