비동기 / 대기 클래스 생성자


169

현재 async/await클래스 생성자 함수 내 에서 사용하려고 합니다. 이것은 e-mail내가 작업중 인 Electron 프로젝트에 대한 사용자 정의 태그를 얻을 수 있도록하기 위한 것입니다.

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

이것을 피할 수있는 방법이 있습니까? 내에서 async / await를 사용할 수 있습니까? 콜백이나 .then () 대신에?


6
생성자의 목적은 객체를 할당 한 다음 즉시 반환하는 것입니다. 생성자가 비동기식이어야한다고 생각 하는 이유정확히 더 구체적으로 설명 할 수 있습니까? 우리는 여기서 XY 문제를 다루는 것이 거의 보장되기 때문에 .
Mike 'Pomax'Kamermans

4
@ Mike'Pomax'Kamermans 그것은 가능합니다. 기본적 으로이 요소를로드하는 데 필요한 메타 데이터를 얻으려면 데이터베이스를 쿼리해야합니다. 데이터베이스 쿼리는 비동기 작업이므로 요소를 구성하기 전에 완료 될 때까지 기다리는 방법이 필요합니다. 프로젝트의 나머지 부분에서 대기 / 비동기를 사용하고 연속성을 유지하기 위해 콜백을 사용하지 않고 싶습니다.
Alexander Craggs

@ Mike'Pomax'Kamermans 이것의 전체 컨텍스트는 이메일 클라이언트로, 각 HTML 요소가 비슷해 보이고 각 HTML 요소가 메소드를 <e-mail data-uid="1028"></email>사용하여 정보로 채워집니다 customElements.define().
Alexander Craggs 2016

생성자가 비동기 적이기를 원하지 않습니다. 객체를 반환하는 동기 생성자를 만든 다음 .init()비동기 작업을 수행하는 것과 같은 방법을 사용하십시오 . 게다가, 당신은 sublcass HTMLElement이기 때문에,이 클래스를 사용하는 코드는 그것이 비동기적인 것이라는 것을 전혀 모를 가능성이 매우 높으므로 어쨌든 완전히 다른 해결책을 찾아야 할 것입니다.
jfriend00

답변:


264

이것은 작동 하지 않습니다 .

async키워드 수 있습니다await 으로 표시하는 기능에 사용될 async뿐만 아니라 약속 발생기로 해당 함수를 변환한다. 따라서로 표시된 함수 async는 약속을 반환합니다. 반면에 생성자는 생성중인 객체를 반환합니다. 따라서 우리는 당신이 물건과 약속을 모두 돌려주고 싶은 상황이 있습니다 : 불가능한 상황.

약속을 본질적으로 구문 설탕이기 때문에 약속을 사용할 수있는 곳에서는 async / await 만 사용할 수 있습니다. 생성자는 약속이 아닌 생성 될 객체를 반환해야하므로 생성자에서 약속을 사용할 수 없습니다.

이를 극복하기위한 두 가지 디자인 패턴이 있으며, 둘 다 약속이 있기 전에 발명되었습니다.

  1. 의 사용 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)();
        }
    }
  2. 빌더를 사용하십시오. 나는 이것이 자바 스크립트에서 많이 사용되는 것을 보지 못했지만 이것은 객체를 비동기 적으로 구성해야 할 때 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);
               });
        }
    }

    async / await을 사용한 구현 :

    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정적 함수는 객체에 바인딩되지 않고 클래스에 직접 바인딩되므로 정적 함수 내부에서 일반적으로 사용할 수 없습니다 .

즉, 다음 코드에서

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 () {}
}

의견을 바탕으로 아이디어는 일반적으로 매뉴얼이 init()없지만 기능 이 src또는 href(이 경우에는 data-uid) 와 같은 특정 속성에 연결된 기능을 갖는 html 요소라는 점에 유의하십시오. 새로운 값이 바뀔 때마다 (그리고 생성 중에도 물론 결과 코드 경로를 기다리지 않고) init를 바인딩하고 시작합니다.
Mike 'Pomax'Kamermans

아래 답변이 충분하지 않은 이유에 대해 언급해야합니다 (있는 경우). 아니면 다른 방법으로 해결하십시오.
Augie Gardner

bind첫 번째 예에서 왜 필요한지 궁금 합니다 callback.bind(this)();. this.otherFunc()콜백 과 같은 일을 할 수 있도록 ?
Alexander Craggs 2016 년

1
@AlexanderCraggs this콜백 에서을 참조하는 것이 편리 합니다 myClass. 항상 myObj대신에 사용한다면 this필요하지 않습니다
slebetman

1
현재 언어에 대한 제한 사항이지만 앞으로 const a = await new A()일반 함수와 비동기 함수 를 사용할 수없는 이유를 알 수 없습니다 .
7ynk3r

138

당신 확실히 이것을 있습니다 . 원래:

class AsyncConstructor {
    constructor() {
        return (async () => {

            // All async code here
            this.value = await asyncFunction();

            return this; // when done
        })();
    }
}

수업 사용을 만들려면 :

let instance = await new AsyncConstructor();

이 솔루션에는 몇 가지 단점이 있습니다.

super참고 :를 사용해야 super하는 경우 비동기 콜백 내에서 호출 할 수 없습니다.

TypeScript 참고 : 생성자가 Promise<MyClass>대신 형식 을 반환하기 때문에 TypeScript에 문제가 발생합니다 MyClass. 내가 아는 것을 해결할 수있는 확실한 방법은 없습니다. @blitter가 제안한 한 가지 잠재적 방법 /** @type {any} */은 생성자 본문의 시작 부분에 두는 것 입니다. 그러나 이것이 모든 상황에서 작동하는지는 알 수 없습니다.


1
@PAStheLoD 나는 그것이 반환없이 객체로 해결할 것이라고 생각하지 않지만 당신은 그것이 그렇게 스펙을 검토하고 업데이트 할 것이라고 말하는 것입니다 ...
Downgoat

2
@JuanLanus async 블록은 매개 변수를 자동으로 캡처하므로 인수 x의 경우에만 수행constructor(x) { return (async()=>{await f(x); return this})() }
Downgoat

1
@PAStheLoD : return thisconstructor자동으로 수행 되기 때문에 필요 하지만 비동기 IIFE는 필요하지 않으며 빈 객체를 반환하게됩니다.
Dan Dascalescu 2016 년

1
현재 ES 3.5, ES2017, ES2018을 대상으로하는 TS 3.5.1 기준으로 생성자에서 리턴을 수행하는 경우 다음과 같은 오류 메시지가 표시됩니다. "반환 유형의 생성자 서명은 클래스의 인스턴스 유형입니다. " IIFE의 유형은 Promise <this>이며 클래스가 Promise <T>가 아니기 때문에 어떻게 작동하는지 알 수 없습니다. ( 'this'이외의 것을 반환 할 수 있습니까?) 따라서 두 반환이 모두 필요하지 않습니다. (컴파일 오류가 발생하기 때문에 외부가 조금 더 나쁩니다.)
PAStheLoD

3
@PAStheLoD 네, 그것은 타입 스크립트 제한입니다. 일반적으로 JS에서 클래스 TT생성 될 때 반환해야 하지만 비동기 기능을 얻으려면 Promise<T>로 변환해야 this하지만 typescript를 혼동합니다. 약속이 완료되면 알 수없는 외부 반환이 필요합니다. 결과적으로이 접근 방식은 TypeScript에서 작동하지 않습니다 (유형 별칭이있는 해킹이없는 한)? 타이프 스크립트 전문가는 아니지만 그렇게 말할 수 없습니다
Downgoat

7

비동기 함수는 약속이므로 클래스의 인스턴스를 반환하는 비동기 함수를 실행하는 클래스에서 정적 함수를 만들 수 있습니다.

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()비동기 함수에서 호출하십시오 .


5

주석을 기반으로 자산로드가있는 다른 모든 HTMLElement가 수행하는 작업을 수행해야합니다. 생성자가 사이드로드 작업을 시작하고 결과에 따라로드 또는 오류 이벤트가 생성되도록합니다.

그렇습니다. 약속을 사용하는 것을 의미하지만 "다른 모든 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 {
  constructor() {
    super();
    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
    let getEmail = new Promise( (resolve, reject) => {
      yourDataBase.getByUID(uid, (err, result) => {
        if (err) return reject(err);
        resolve(result);
      });
    });
    // kick off the promise, which will be async all on its own
    getEmail()
    .then(result => {
      this.renderLoaded(result.message);
    })
    .catch(error => {
      this.renderError(error);
    });
  }
};

customElements.define('e-mail', EmailElement);

그런 다음 renderLoaded / renderError 함수가 이벤트 호출 및 shadow dom을 처리하도록합니다.

  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', ...));
  }

또한 나는 당신의 변화에 유의 idA와 class당신이 몇 가지 이상한 코드를 작성하지 않는 한 오직 당신의 단일 인스턴스 수 있기 때문에, <e-mail>한 페이지에 요소가 고유 한 식별자를 사용하고 요소의 무리에 할당 할 수 없습니다.


2

@Downgoat의 답변을 기반 으로이 테스트 사례를 만들었습니다.
NodeJS에서 실행됩니다. 이것은 setTimeout()호출에 의해 비동기 부분이 제공되는 Downgoat의 코드 입니다.

'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 콜렉션과 같은 레코드입니다.
cooksDAO 인스턴스는 요리사의 데이터를 보유합니다.
불안한 마음으로 나는 cookId를 인수로 제공하는 요리사의 DAO를 인스턴스화 할 수 있었고 인스턴스화는 객체를 만들고 요리사의 데이터로 채울 것입니다.
따라서 생성자에 비동기 작업을 실행할 필요가 있습니다.
나는 쓰고 싶었다 :

let cook = new cooksDAO( '12345' );  

사용 가능한 속성을 갖기 위해 cook.getDisplayName() .
이 솔루션을 사용하면 다음을 수행해야합니다.

let cook = await new cooksDAO( '12345' );  

이상과 매우 유사합니다.
또한 async함수 내 에서이 작업을 수행해야 합니다.

내 B 계획은 ins 함수를 사용하는 @ slebetman 제안에 따라 생성자에서 데이터를로드하지 않고 다음과 같이 수행하는 것입니다.

let cook = new cooksDAO( '12345' );  
async cook.getData();

규칙을 어 기지 않습니다.


2

구문에서 비동기 메서드를 사용 하시겠습니까 ???

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

2

스톱 갭 솔루션

async init() {... return this;}메소드 를 생성 한 다음 new MyClass().init()평소에 그냥 말할 때마다 수행 할 수 있습니다 new MyClass().

코드를 사용하는 모든 사람과 자신에게 항상 객체를 인스턴스화하는 데 의존하기 때문에 이것은 깨끗하지 않습니다. 그러나 코드에서 특정 위치 또는이 위치에서만이 객체를 사용하는 경우 문제가 없을 수 있습니다.

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를 수행 할 수 Object.create(AsyncOnlyObject.prototype)있습니다. 직접 사용하는 팩토리 함수를 만들어야 합니다.

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}

(제작에 사용하지 마십시오 : 키워드 인수에 대한 래퍼를 작성하는 적절한 방법인지 여부와 같은 복잡한 시나리오를 고려하지 않았습니다.)


2

다른 사람들과 달리, 당신은 그것을 작동시킬 수 있습니다.

JavaScript classes는 constructor다른 클래스의 인스턴스조차도 문자 그대로 모든 것을 반환 할 수 있습니다 . 따라서 Promise클래스의 생성자에서 실제 인스턴스로 확인되는를 반환 할 수 있습니다 .

아래는 예입니다.

export class Foo {

    constructor() {

        return (async () => {

            // await anything you want

            return this; // Return the newly-created instance
        }).call(this);
    }
}

그런 다음 Foo이 방법으로 인스턴스를 만듭니다 .

const foo = await new Foo();

1

피할 수 있다면 extend클래스를 함께 피하고 함수 구성을 생성자 로 사용할 수 있습니다 . 클래스 멤버 대신 범위에서 변수를 사용할 수 있습니다.

async function buildA(...) {
  const data = await fetch(...);
  return {
    getData: function() {
      return data;
    }
  }
}

간단하게 사용하세요

const a = await buildA(...);

typescript 또는 flow를 사용하는 경우 생성자 의 인터페이스를 적용 할 수도 있습니다.

Interface A {
  getData: object;
}

async function buildA0(...): Promise<A> { ... }
async function buildA1(...): Promise<A> { ... }
...

0

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

0

메시지를 반환하는 익명의 비동기 함수를 즉시 호출하여 메시지 변수로 설정할 수 있습니다. 이 패턴에 익숙하지 않은 경우 즉시 호출 된 함수 표현식 (IEFES)을 살펴볼 수 있습니다. 이것은 매력처럼 작동합니다.

var message = (async function() { return await grabUID(uid) })()

-1

@ slebetmen의 대답은 왜 이것이 작동하지 않는지를 잘 설명합니다. 이 답변에 제시된 두 가지 패턴 외에도 다른 옵션은 사용자 정의 비동기 게터를 통해서만 비동기 속성에 액세스하는 것입니다. 그런 다음 constructor ()은 속성의 비동기 생성을 트리거 할 수 있지만 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;
    }
  }
}

-2

다른 대답은 명백하지 않습니다. 생성자에서 비동기 함수를 호출하기 만하면됩니다.

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>
    `
}

여기에있는 또 하나의 "명백한"대답 처럼 , 이것은 프로그래머가 일반적으로 생성자에게 기대하는 것을 수행하지 않을 것입니다. 즉, 객체가 생성 될 때 내용이 설정됩니다.
Dan Dascalescu

2
@DanDascalescu 그것은 질문자가 요구하는 정확히 비동기식으로 설정됩니다. 요점은 질문이 필요하지 않은 객체가 생성 될 때 내용이 동 기적으로 설정되지 않는다는 것입니다. 그래서 생성자 내에서 await / async를 사용하는 것이 중요합니다. 비동기 함수를 호출하여 생성자에서 원하는만큼 대기 / 비동기를 호출하는 방법을 설명했습니다. 나는 그 질문에 완벽하게 대답했다.
Navigateur

@ Navigateur는 내가 생각해 낸 것과 동일한 솔루션이지만 다른 유사한 질문에 대한 의견은 이 방법으로 수행해서는 안된다고 제안합니다. 약속에서 주요 문제는 생성자에서 잃어 버렸으며 이것은 반 패턴입니다. 생성자에서 비동기 함수를 호출하는이 방법을 권장하는 참조가 있습니까?
Marklar

1
@ Marklar 참조가 없습니다. 왜 필요한가요? 당신이 처음에 그것을 필요로하지 않는다면 무언가가 "잃어버린"것이 중요하지 않습니다. 그리고 약속이 필요하다면 this.myPromise =어떤 의미에서도 반 패턴이 아닌 (일반적인 의미에서) 추가하는 것은 사소한 일입니다. 구성시, 리턴 값 자체가없고, 어쨌든 우리를 단순하게 추가하는 비동기 알고리즘을 시작해야하는 경우에는 완전히 유효한 경우가 있습니다. 따라서 이것을하지 말라고 조언하는 사람은 무언가를 오해하고 있습니다
Navigateur

1
답장을 보내 주셔서 감사합니다. Stackoverflow에 대한 상충되는 답변으로 인해 더 자세한 내용을 찾고있었습니다. 이 시나리오에 대한 모범 사례를 확인하고 싶었습니다.
Marklar

-2

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

innerResolve(this)this그래도 여전히 그렇듯이 작동하지 않습니다 . 이것은 끝없는 재귀 해상도로 이어집니다.
Bergi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.