비동기/대기 클래스 컨스트럭터
은 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★async/await
이치노은 제가 커스텀을 수 하기 .e-mail
내가 하고 있는 일렉트로닉 프로젝트의 태그를 붙입니다.
customElements.define('e-mail', class extends HTMLElement {
async constructor() {
super()
let uid = this.getAttribute('data-uid')
let message = await grabUID(uid)
const shadowRoot = this.attachShadow({mode: 'open'})
shadowRoot.innerHTML = `
<div id="email">A random email message has appeared. ${message}</div>
`
}
})
그러나 현재 프로젝트가 작동하지 않고 다음 오류가 발생합니다.
Class constructor may not be an async method
이 안에서 비동기/대기 기능을 사용할 수 있도록 회피할 수 있는 방법이 있습니까?콜백이나 .then()을 필요로 하지 않습니다.
이건 절대 안 돼
async
를 지정하면, 「」는 허가됩니다.await
async
그 기능을 약속 생성기로 변환하기도 합니다.따라서 다음과 같이 표시된async
약속에 답할 것이다.반면 생성자는 생성 중인 개체를 반환합니다.따라서 우리는 물건과 약속을 모두 반환하고 싶은 상황이 있습니다. 불가능한 상황입니다.
약속은 기본적으로 약속의 구문설탕이기 때문에 약속을 사용할 수 있는 경우에만 비동기/대기 명령을 사용할 수 있습니다.컨스트럭터는 컨스트럭터가 컨스트럭터가 아니라 컨스트럭터 오브젝트를 반환해야 하기 때문에 컨스트럭터에서 약속을 사용할 수 없습니다.
이를 극복하기 위한 두 가지 디자인 패턴이 있습니다. 두 가지 모두 약속보다 먼저 발명되었습니다.
「」의
init()
는 jQuery와 같은 입니다..ready()
. 에서만 사용할 수init
★★★★★★★★★★★★★★★★★」ready
★★★★사용방법:
var myObj = new myClass(); myObj.init(function() { // inside here you can use myObj });
구현:
class myClass { constructor () { } init (callback) { // do something async and call the callback: callback.bind(this)(); } }
빌더를 사용합니다.javascript에서는 많이 사용되지 않지만, 이것은 오브젝트를 비동기적으로 구성해야 할 때 Java에서 가장 일반적인 회피책 중 하나입니다.물론 빌더 패턴은 복잡한 파라미터를 많이 필요로 하는 객체를 작성할 때 사용됩니다.바로 비동기식 빌더의 사용 사례입니다.차이점은 비동기 빌더는 개체를 반환하지 않고 해당 개체의 약속을 반환한다는 것입니다.
사용방법:
myClass.build().then(function(myObj) { // myObj is returned by the promise, // not by the constructor // or builder }); // with async/await: async function foo () { var myObj = await myClass.build(); }
구현:
class myClass { constructor (async_param) { if (typeof async_param === 'undefined') { throw new Error('Cannot be called directly'); } } static build () { return doSomeAsyncStuff() .then(function(async_result){ return new myClass(async_result); }); } }
비동기/대기 구현:
class myClass { constructor (async_param) { if (typeof async_param === 'undefined') { throw new Error('Cannot be called directly'); } } static async build () { var async_result = await doSomeAsyncStuff(); return new myClass(async_result); } }
주의: 위의 예에서는 비동기 빌더에 대한 약속을 사용하고 있지만 엄밀하게는 필요하지 않습니다.콜백을 받아들이는 빌더를 쉽게 작성할 수 있습니다.
스태틱 함수 내부의 호출 함수에 주의해 주세요.
와는 전혀 가 없습니다. 「」는 「」입니다.this
을 실시하는 로부터 온 에게는, 만, 즉, 「메서드명의 자동 해결을 실시하는 언어」가입니다.this
키워드를 지정합니다.
this
키워드는 인스턴스화된 오브젝트를 나타냅니다.그래서 이렇게 안 돼요.this
는 어떤 .static에 있기 입니다.
즉, 다음과 같은 코드입니다.
class A {
static foo () {}
}
다음 작업을 수행할 수 없습니다.
var a = new A();
a.foo() // NOPE!!
대신 다음과 같이 불러야 합니다.
A.foo();
따라서 다음 코드가 발생하면 오류가 발생합니다.
class A {
static foo () {
this.bar(); // you are calling this as static
// so bar is undefinned
}
bar () {}
}
하려면 , 「 」를 설정합니다.bar
" " " " " " " " " 。
function bar1 () {}
class A {
static foo () {
bar1(); // this is OK
A.bar2(); // this is OK
}
static bar2 () {}
}
이를 위해서는 컨스트럭터에서 즉시 호출된 비동기 함수식을 반환해야 합니다. IIAFE
는 매우 입니다.await
비동기 기능 외부, 탑레벨 대기 기능을 사용할 수 있게 되기 전:
(async () => {
await someFunction();
})();
하고 그 를 """로 반환합니다.this
:
// Sample async function to be used in the async constructor
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
class AsyncConstructor {
constructor(value) {
return (async () => {
// Call async functions here
await sleep(500);
this.value = value;
// Constructors return `this` implicitly, but this is an IIFE, so
// return `this` explicitly (else we'd return an empty object).
return this;
})();
}
}
(async () => {
console.log('Constructing...');
const obj = await new AsyncConstructor(123);
console.log('Done:', obj);
})();
클래스를 인스턴스화하려면 다음을 사용합니다.
const instance = await new AsyncConstructor(...);
TypeScript의 경우 생성자의 유형이 클래스 유형을 반환하는 약속 대신 클래스 유형임을 확인해야 합니다.
class AsyncConstructor {
constructor(value) {
return (async (): Promise<AsyncConstructor> => {
// ...
return this;
})() as unknown as AsyncConstructor; // <-- type assertion
}
}
단점
- 비동기 생성자를 사용하여 클래스를 확장하면 제한이 있습니다.할 필요가
super
클래스이 생성자를 따로 .await
「」를 사용해 주세요.await
오류 TypeScript 2337이Super calls are not permitted outside constructors or in nested functions inside constructors.
- 컨스트럭터 함수가 Promise를 반환하도록 하는 것은 "나쁜 관행"이라는 주장이 제기되었습니다.
를 판단하고 를 이이로 .await
.
비동기 함수는 약속이기 때문에 클래스의 인스턴스를 반환하는 비동기 함수를 실행하는 정적 함수를 클래스에 만들 수 있습니다.
class Yql {
constructor () {
// Set up your class
}
static init () {
return (async function () {
let yql = new Yql()
// Do async stuff
await yql.build()
// Return instance
return yql
}())
}
async build () {
// Do stuff with await if needed
}
}
async function yql () {
// Do this instead of "new Yql()"
let yql = await Yql.init()
// Do stuff with yql instance
}
yql()
★★와의 let yql = await Yql.init()
이치노
다른 사람들이 말한 것과 달리, 당신은 그것을 작동시킬 수 있습니다.
class
는 말 es에서 할 수 .constructor
있다하다', '반환하다', '반환하다', '반환하다', '반환하다', '반환하다' 할 수 요.Promise
클래스 생성자에서 실제 인스턴스로 해결합니다.
다음은 예를 제시하겠습니다.
export class Foo {
constructor() {
return (async () => {
// await anything you want
return this; // Return the newly-created instance
})();
}
}
다음 ', 하다, 하다의 예를 만들어 .Foo
방법 명령어:
const foo = await new Foo();
미봉책 솔루션
만들 수 요.async init() {... return this;}
실행해 주세요.new MyClass().init()
'그냥 해'라고만 할 때마침new MyClass()
.
이 방법은 코드를 사용하는 모든 사용자와 사용자가 항상 이렇게 개체를 인스턴스화하기 때문에 안전하지 않습니다.단, 코드의 특정 장소 또는 두 곳에서만 이 개체를 사용하는 경우에는 문제가 없을 수 있습니다.
, 이 없기 에 중대한 문제가 ES를 에는 ES를 반환하기만 undefined
왜냐하면 컨스트럭터는 아무것도 반환하지 않기 때문입니다.이런 걸 하는 게 더 나을 것 같아
가장 좋은 방법은 다음과 같습니다.
class AsyncOnlyObject {
constructor() {
}
async init() {
this.someField = await this.calculateStuff();
}
async calculateStuff() {
return 5;
}
}
async function newAsync_AsyncOnlyObject() {
return await new AsyncOnlyObject().init();
}
newAsync_AsyncOnlyObject().then(console.log);
// output: AsyncOnlyObject {someField: 5}
공장 출하시 방법 솔루션(약간 우수)
단, 실수로 새로운 AsyncOnlyObject를 실행할 수 있습니다.아마 다음 기능을 직접 사용하는 공장 함수를 작성해야 합니다.
async function newAsync_AsyncOnlyObject() {
return await Object.create(AsyncOnlyObject.prototype).init();
}
newAsync_AsyncOnlyObject().then(console.log);
// output: AsyncOnlyObject {someField: 5}
이렇게 이 ( 으악) 부르는할 수 요.postProcess_makeAsyncInit(AsyncOnlyObject)
, 여기서는extends
이는 서브클래스의 의미론(서브클래스는 부모클래스의 설계계약에 따라야 하며 추가 작업을 수행할 수 있습니다.비동기 서브클래스는 부모클래스와 같은 방법으로 초기화할 수 없기 때문에 부모클래스가 비동기적이지 않으면 이상합니다).
추상화된 솔루션(확장/하위 클래스 버전)
class AsyncObject {
constructor() {
throw new Error('classes descended from AsyncObject must be initialized as (await) TheClassName.anew(), rather than new TheClassName()');
}
static async anew(...args) {
var R = Object.create(this.prototype);
R.init(...args);
return R;
}
}
class MyObject extends AsyncObject {
async init(x, y=5) {
this.x = x;
this.y = y;
// bonus: we need not return 'this'
}
}
MyObject.anew('x').then(console.log);
// output: MyObject {x: "x", y: 5}
(실가동 시에는 사용하지 마십시오.이것이 키워드 인수의 래퍼를 작성하는 적절한 방법인지 등 복잡한 시나리오는 생각해 본 적이 없습니다.)
코멘트를 바탕으로 자산을 로드하는 다른 모든 HTMLlement와 마찬가지로 컨스트럭터가 사이드 사이드 액션을 시작하도록 하고 결과에 따라 로드 또는 오류 이벤트를 생성하도록 해야 합니다.
네, 이것은 약속을 사용하는 것을 의미하지만, "다른 모든 HTML 요소와 같은 방법으로 일을 처리한다"는 의미도 있기 때문에 좋은 회사에 있을 수 있습니다.예:
var img = new Image();
img.onload = function(evt) { ... }
img.addEventListener("load", evt => ... );
img.onerror = function(evt) { ... }
img.addEventListener("error", evt => ... );
img.src = "some url";
에 의해, 이 로드는 「」, 「」로 종료됩니다.★★★★★★★★★★★★★★★★★★★★★★★,onload
하면, 「이러다」, 「이러다만, 「이러다」로 .onerror
그럼, 당신만의 수업도 이 일을 하도록 하세요.
class EMailElement extends HTMLElement {
connectedCallback() {
this.uid = this.getAttribute('data-uid');
}
setAttribute(name, value) {
super.setAttribute(name, value);
if (name === 'data-uid') {
this.uid = value;
}
}
set uid(input) {
if (!input) return;
const uid = parseInt(input);
// don't fight the river, go with the flow, use a promise:
new Promise((resolve, reject) => {
yourDataBase.getByUID(uid, (err, result) => {
if (err) return reject(err);
resolve(result);
});
})
.then(result => {
this.renderLoaded(result.message);
})
.catch(error => {
this.renderError(error);
});
}
};
customElements.define('e-mail', EmailElement);
그런 다음 renderLoaded/renderError 함수에 이벤트 호출과 섀도우 돔을 처리합니다.
renderLoaded(message) {
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<div class="email">A random email message has appeared. ${message}</div>
`;
// is there an ancient event listener?
if (this.onload) {
this.onload(...);
}
// there might be modern event listeners. dispatch an event.
this.dispatchEvent(new Event('load'));
}
renderFailed() {
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<div class="email">No email messages.</div>
`;
// is there an ancient event listener?
if (this.onload) {
this.onerror(...);
}
// there might be modern event listeners. dispatch an event.
this.dispatchEvent(new Event('error'));
}
, 나는 의 ,, 가, 가, 내, 내를 변경했습니다.id
a까지class
왜냐하면, 않는 한, 하나의 할 수 있기 <e-mail>
고유한 식별자를 사용하여 여러 요소에 할당할 수 없습니다.
보통 새 인스턴스를 반환하는 정적 비동기 방식을 선호합니다만, 다른 방법이 있습니다.말 그대로 건설업자를 기다리는 것에 가깝습니다.TypeScript와 연동됩니다.
class Foo {
#promiseReady;
constructor() {
this.#promiseReady = this.#init();
}
async #init() {
await someAsyncStuff();
return this;
}
ready() {
return this.promiseReady;
}
}
let foo = await new Foo().ready();
저는 @Downgoat의 답변을 바탕으로 이 테스트 케이스를 만들었습니다.
Node JS node node node 。은 Downgoat, Downgoat에 됩니다.setTimeout()
'use strict';
const util = require( 'util' );
class AsyncConstructor{
constructor( lapse ){
this.qqq = 'QQQ';
this.lapse = lapse;
return ( async ( lapse ) => {
await this.delay( lapse );
return this;
})( lapse );
}
async delay(ms) {
return await new Promise(resolve => setTimeout(resolve, ms));
}
}
let run = async ( millis ) => {
// Instatiate with await, inside an async function
let asyncConstructed = await new AsyncConstructor( millis );
console.log( 'AsyncConstructor: ' + util.inspect( asyncConstructed ));
};
run( 777 );
DAO를 사용하다
DAO를 사용하다MongoDB가 있습니다.
됩니다.DAO 인스턴스에는 요리사의 데이터가 저장됩니다.
내 마음속으로는 cookId를 인수로 제공하는 요리사의 DAO를 인스턴스화할 수 있고, 인스턴스화는 객체를 생성하여 요리사의 데이터로 채울 수 있다.
따라서 비동기적인 것을 컨스트럭터로 실행해야 합니다.
쓰고 요.
let cook = new cooksDAO( '12345' );
cook.getDisplayName()
.
이 솔루션에서는 다음 작업을 수행해야 합니다.
let cook = await new cooksDAO( '12345' );
이상과 매우 유사합니다.
그리고 이거는 실내에서 해야 돼요async
★★★★★★ 。
저의 B-plan은 @slebetman의 제안에 따라 데이터를 컨스트럭터에서 로드하지 않고 init 함수를 사용하여 다음과 같은 작업을 수행하는 것이었습니다.
let cook = new cooksDAO( '12345' );
async cook.getData();
규칙을 어기진 않아요
컨스트럭터에서 비동기 메서드를 사용합니다.
constructor(props) {
super(props);
(async () => await this.qwe(() => console.log(props), () => console.log(props)))();
}
async qwe(q, w) {
return new Promise((rs, rj) => {
rs(q());
rj(w());
});
}
피할 수 있다면 extend
, 클래스를 모두 회피하고 함수 합성을 컨스트럭터로 사용할 수 있습니다.클래스 멤버 대신 스코프의 변수를 사용할 수 있습니다.
async function buildA(...) {
const data = await fetch(...);
return {
getData: function() {
return data;
}
}
}
간단하게 사용할 수 있습니다.
const a = await buildA(...);
타이프 스크립트 또는 플로우를 사용하고 있는 경우는, 컨스트럭터의 인터페이스를 적용할 수도 있습니다.
Interface A {
getData: object;
}
async function buildA0(...): Promise<A> { ... }
async function buildA1(...): Promise<A> { ... }
...
Proxy를 할 수 .construct
이렇게 하기 위한 코드는 다음과 같습니다.
const SomeClass = new Proxy(class A {
constructor(user) {
this.user = user;
}
}, {
async construct(target, args, newTarget) {
const [name] = args;
// you can use await in here
const user = await fetch(name);
// invoke new A here
return new target(user);
}
});
const a = await new SomeClass('cage');
console.log(a.user); // user info
call()을 사용한 빌더 패턴의 변화:
function asyncMethod(arg) {
function innerPromise() { return new Promise((...)=> {...}) }
innerPromise().then(result => {
this.setStuff(result);
}
}
const getInstance = async (arg) => {
let instance = new Instance();
await asyncMethod.call(instance, arg);
return instance;
}
나는 이런 상황에 처했고 결국 IIFE를 사용하게 되었다.
// using TypeScript
class SomeClass {
constructor() {
// do something here
}
doSomethingAsync(): SomeClass {
(async () => await asyncTask())();
return this;
}
}
const someClass = new SomeClass().doSomethingAsync();
비동기 태스크에 의존하는 다른 태스크가 있는 경우 IIFE 실행 완료 후 실행할 수 있습니다.
여기에는 많은 훌륭한 지식과 사려 깊은 답변이 있습니다.즉, 다음에 설명하는 기술은 매우 간단하고, 비재귀적이며, 비동기 호환성이 있으며, 규칙에 따라 작동합니다.더 중요한 것은 아직 여기서 제대로 다루지 않았다고 생각합니다.잘못됐다면 정정해 주세요!
메서드 호출 대신 단순히 II(A)를 할당합니다.인스턴스 프로포트에 대한 FE:
// it's async-lite!
class AsyncLiteComponent {
constructor() {
// our instance includes a 'ready' property: an IIAFE promise
// that auto-runs our async needs and then resolves to the instance
// ...
// this is the primary difference to other answers, in that we defer
// from a property, not a method, and the async functionality both
// auto-runs and the promise/prop resolves to the instance
this.ready = (async () => {
// in this example we're auto-fetching something
this.msg = await AsyncLiteComponent.msg;
// we return our instance to allow nifty one-liners (see below)
return this;
})();
}
// we keep our async functionality in a static async getter
// ... technically (with some minor tweaks), we could prefetch
// or cache this response (but that isn't really our goal here)
static get msg() {
// yes I know - this example returns almost immediately (imagination people!)
return fetch('data:,Hello%20World%21').then((e) => e.text());
}
}
간단해 보이는데, 어떻게 사용하는 거죠?
// Ok, so you *could* instantiate it the normal, excessively boring way
const iwillnotwait = new AsyncLiteComponent();
// and defer your waiting for later
await iwillnotwait.ready
console.log(iwillnotwait.msg)
// OR OR OR you can get all async/awaity about it!
const onlywhenimready = await new AsyncLiteComponent().ready;
console.log(onlywhenimready.msg)
// ... if you're really antsy you could even "pre-wait" using the static method,
// but you'd probably want some caching / update logic in the class first
const prefetched = await AsyncLiteComponent.msg;
// ... and I haven't fully tested this but it should also be open for extension
class Extensior extends AsyncLiteComponent {
constructor() {
super();
this.ready.then(() => console.log(this.msg))
}
}
const extendedwaittime = await new Extensior().ready;
글을 올리기 전에 @slebetman의 포괄적인 답변 코멘트에서 이 기술의 실행 가능성에 대해 간단히 논의했습니다.나는 완전히 해고된 것에 대해 완전히 납득하지 못했기 때문에, 그것을 더 토론하거나 해체할 수 있도록 열어두려고 생각했다.최선을 다해 주세요:)
메시지를 반환하는 익명 비동기 함수를 즉시 호출하여 메시지 변수로 설정할 수 있습니다.이 패턴에 익숙하지 않은 경우 즉시 호출된 함수 표현(IEFES)을 살펴보는 것이 좋습니다.이거 참 잘 먹힐 것 같아.
var message = (async function() { return await grabUID(uid) })()
다른 답들은 명백한 것을 놓치고 있다.컨스트럭터에서 비동기 함수를 호출하기만 하면 됩니다.
constructor() {
setContentAsync();
}
async setContentAsync() {
let uid = this.getAttribute('data-uid')
let message = await grabUID(uid)
const shadowRoot = this.attachShadow({mode: 'open'})
shadowRoot.innerHTML = `
<div id="email">A random email message has appeared. ${message}</div>
`
}
해서 더 돼요.then
합니다. Promise
그때 쓸 수 하게 됩니다.Promise.resolve
const asyncSymbol = Symbol();
class MyClass {
constructor() {
this.asyncData = null
}
then(resolve, reject) {
return (this[asyncSymbol] = this[asyncSymbol] || new Promise((innerResolve, innerReject) => {
this.asyncData = { a: 1 }
setTimeout(() => innerResolve(this.asyncData), 3000)
})).then(resolve, reject)
}
}
async function wait() {
const asyncData = await new MyClass();
alert('run 3s later')
alert(asyncData.a)
}
@slebetmen의 대답은 왜 이것이 효과가 없는지를 잘 설명해 준다.이 답변에 제시된 두 가지 패턴 외에 다른 옵션은 커스텀 비동기 getter를 통해서만 비동기 속성에 액세스하는 것입니다.그런 다음 컨스트럭터()는 속성의 비동기 작성을 트리거할 수 있지만 getter는 속성을 사용하거나 반환하기 전에 해당 속성을 사용할 수 있는지 확인합니다.
이 접근법은 글로벌개체를 시작할 때 초기화하고 모듈 내에서 초기화할 때 특히 유용합니다.에서 index.js
.단순히 '를 사용할 수 있습니다.require
글로벌 오브젝트가 필요한 모든 장소에서 모듈을 사용할 수 있습니다.
사용.
const instance = new MyClass();
const prop = await instance.getMyProperty();
실행
class MyClass {
constructor() {
this.myProperty = null;
this.myPropertyPromise = this.downloadAsyncStuff();
}
async downloadAsyncStuff() {
// await yourAsyncCall();
this.myProperty = 'async property'; // this would instead by your async call
return this.myProperty;
}
getMyProperty() {
if (this.myProperty) {
return this.myProperty;
} else {
return this.myPropertyPromise;
}
}
}
비동기 컨스트럭터에 가장 가까운 방법은 아직 모든 메서드에 포함되지 않은 경우 실행이 완료될 때까지 기다리는 것입니다.
class SomeClass {
constructor() {
this.asyncConstructor = (async () => {
// Perform asynchronous operations here
})()
}
async someMethod() {
await this.asyncConstructor
// Perform normal logic here
}
}
언급URL : https://stackoverflow.com/questions/43431550/async-await-class-constructor
'source' 카테고리의 다른 글
변수를 사용하여 객체 속성에 동적으로 액세스 (0) | 2022.12.28 |
---|---|
MySQL - 테이블 복제 (0) | 2022.12.18 |
Redux 애플리케이션에서 코드 분할을 위한 부하 감소기를 동적으로 로드하는 방법은 무엇입니까? (0) | 2022.12.18 |
스크래피 키 오류: z (freebsd) (0) | 2022.12.18 |
C의 반환 값을 둘러싼 괄호 (0) | 2022.12.18 |