Thenable: JavaScript 객체를 대기 친화적으로 만드는 방법과 유용한 이유
그러면 가능이란 무엇입니까?
이 짧은 게시물은 모든 JavaScript 클래스 또는 객체 리터럴에
.then(onFulfilled, onRejected)
메서드를 추가하여 await
와 잘 작동하도록 할 수 있음을 상기시키기 위한 것입니다. 개체가 비동기 작업을 수행할 때 유용합니다.많은 C# 개발자는 "사용자 지정 대기자"의 개념에 익숙합니다(Stephen Toub의 "Await anything" 참조). 흥미롭게도 JavaScript에서는 문자 그대로 모든 것이 있는 그대로 기다릴 수 있지만(예: try
(await true) === true
) 언어는 C# awaitables: thenable objects 또는 Thenables와 유사한 기능도 제공합니다.Thenable은 약속이 아니지만
await
연산자의 오른쪽에서 의미 있게 사용할 수 있으며 , Promise.race()
등과 같은 많은 표준 JavaScript API에서 허용됩니다. 예를 들어 thenable
를 a로 래핑할 수 있습니다. 다음과 같이 선의의 약속을 합니다.const promise = Promise.resolve(thenable);
이면에서 작동하는 방식에 대해 더 자세히 알고 싶다면 V8 블로그를 참조하세요. "Faster async functions and promises" .
샘플 사용 사례
먼저 jQuery
Deffered
및 .NET Deferred
에서 영감을 받은 TaskCompletionSource
객체를 생성해 보겠습니다.function createDeferred() {
let resolve, reject;
const promise = new Promise((...args) =>
[resolve, reject] = args);
return Object.freeze({
resolve,
reject,
then: promise.then.bind(promise)
});
}
const deferred = createDeferred();
// resolve the deferred in 2s
setTimeout(deferred.resolve, 2000);
await deferred;
완전성을 위해 the same in TypeScript .
이제 약간 인위적이지만
thenable
가 적절한 리소스 정리(이 경우 타이머)에 어떻게 유용할 수 있는지 보여주는 좀 더 예시적인 예가 되기를 바랍니다.function createStoppableTimer(ms) {
let cleanup = null;
const promise = new Promise(resolve => {
const id = setTimeout(resolve, ms);
cleanup = () => {
cleanup = null;
clearTimeout(id);
resolve(false);
}
});
return Object.freeze({
stop: () => cleanup?.(),
then: promise.then.bind(promise)
});
}
const timeout1 = createStoppableTimeout(1000);
const timeout2 = createStoppableTimeout(2000);
try {
await Promise.race([timeout1, timeout2]);
}
finally {
timeout1.stop();
timeout2.stop();
}
확실히 우리는 속성으로
promise
를 노출할 수 있었습니다.await Promise.race([timeout1.promise, timeout2.promise]);
그것은 효과가 있지만 나는 팬이 아닙니다.
asyncWorkflow
가 비동기 작업을 나타내는 곳은 속성 중 하나가 아니라 await asyncWorkflow
자체가 가능해야 한다고 생각합니다. 그것이 asyncWorkflow.then(onFulfilled, onRejected)
구현이 도움이 되는 곳입니다.다음은 이벤트 핸들러 구독을 적절하게 정리하면서 임의의
EventTarget
이벤트를 비동기식으로 기다리는 방법에 대한 또 하나의 예입니다. 다음 2초 이내에 팝업 창이 닫히기를 기다리고 있습니다.const eventObserver = observeEvent(
popup, "close", event => event.type);
const timeout = createStoppableTimeout(2000);
try {
await Promise.race([eventObserver, timeout]);
}
catch (error) {
console.error(error);
}
finally {
timeout.stop();
eventObserver.close();
}
This is what the
observeEvent
implementation may look like (note how it returns an object with then
and close
methods):function observeEvent(eventSource, eventName, onevent) {
let cleanup = null;
const promise = observe();
return Object.freeze({
close: () => cleanup?.(),
then: promise.then.bind(promise)
});
// an async helper to wait for the event
async function observe() {
const eventPromise = new Promise((resolve, reject) => {
const handler = (...args) => {
try {
resolve(onevent?.(...args));
}
catch (error) {
reject(error);
}
finally {
cleanup?.();
}
};
cleanup = () => {
cleanup = null;
eventSource.removeEventListener(handler);
}
eventSource.addEventListener(
eventName, handler, { once: true });
});
try {
return await eventPromise;
}
finally {
cleanup?.();
}
}
}
I use this pattern a lot, as it helps with properly structured error handling and scoped resources management. The errors are propagated from inside the event handler (if any) by rejecting the internal promise, so await eventObserver
will rethrow them.
const eventObserver = observeEvent(
popup, "close", event => "closed!");
const timeout = createStoppableTimeout(2000);
try using (eventObserver, timeout) {
await Promise.race([eventObserver, timeout]);
}
정리 메서드를 명시적으로 호출할 필요가 없습니다.
나는 미래의 블로그 게시물에서 Ron Buckton의 또 다른 중요한 TC39 제안ECMAScript Cancellation을 오늘 대안으로 사용할 수 있는 것을 포함하여 더 자세히 다루기를 희망합니다.
읽어 주셔서 감사합니다! 아래 또는 에 댓글을 남겨주세요.
Reference
이 문제에 관하여(Thenable: JavaScript 객체를 대기 친화적으로 만드는 방법과 유용한 이유), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/noseratio/we-can-make-any-javascript-object-await-able-with-then-method-1apl텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)