Async / Await Sınıfı Oluşturucu


169

Şu anda, async/awaitbir sınıf yapıcı işlevi içinde kullanmaya çalışıyorum . Bu, e-mailüzerinde çalıştığım bir Electron projesi için özel bir etiket alabilmem için.

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

Ancak şu anda proje şu hatayla çalışmıyor:

Class constructor may not be an async method

Bunu atlatmanın bir yolu var mı? Geri arama veya .then () yerine?


6
Bir kurucunun amacı size bir nesne tahsis etmek ve hemen geri dönmek. Eğer çok daha spesifik üzerinde olabilir neden tam size yapıcı zaman uyumsuz olması gerektiğini düşünüyorsunuz? Çünkü burada bir XY problemiyle uğraşmamız neredeyse garantimiz altında .
Mike 'Pomax' Kamermans

4
@ Mike'Pomax'Kamermans Bu oldukça mümkün. Temel olarak, bu öğeyi yüklemek için gerekli meta verileri almak için bir veritabanı sorgulamak gerekiyor. Veritabanını sorgulamak eşzamansız bir işlemdir ve bu nedenle öğeyi oluşturmadan önce bunun tamamlanmasını beklemenin bir yolunu istiyorum. Projenin geri kalanında beklediğim / zaman uyumsuz kullandığım ve sürekliliği korumak istediğim için geri arama yapmamayı tercih ederim.
Alexander Craggs

@ Mike'Pomax'Kamermans Bunun tüm içeriği, her HTML öğesinin benzer <e-mail data-uid="1028"></email>ve oradan benzer göründüğü bir e-posta istemcisidir customElements.define().
Alexander Craggs

Bir kurucunun zaman uyumsuz olmasını istemezsiniz. Nesnenizi döndüren bir eşzamanlı kurucu oluşturun ve ardından .init()eşzamansız şeyler yapmak gibi bir yöntem kullanın . Ayrıca, sublcass HTMLElement olduğunuz için, bu sınıfı kullanan kodun async bir şey olduğu hakkında hiçbir fikre sahip olmaması son derece olasıdır, bu yüzden yine de tamamen farklı bir çözüm aramak zorunda kalacaksınız.
jfriend00

Yanıtlar:


264

Bu asla işe yaramaz.

asyncAnahtar kelime verir awaitolarak işaretlenmiş bir işlevde kullanılacak asyncama aynı zamanda bir söz jeneratörüne bu işlevi dönüştürür. Yani ile işaretlenmiş bir fonksiyon asyncbir söz verecektir. Öte yandan bir kurucu oluşturduğu nesneyi döndürür. Böylece hem bir nesneyi hem de bir söz vermek istediğiniz bir durumumuz var: imkansız bir durum.

Async / await'i yalnızca vaatleri kullanabileceğiniz yerlerde kullanabilirsiniz, çünkü bunlar vaatler için sözdizimi şekerleridir. Bir kurucu vaatleri kullanamazsınız çünkü kurucu bir vaat değil, oluşturulacak nesneyi döndürmelidir.

Bunun üstesinden gelmek için iki tasarım deseni vardır, her ikisi de sözler gerçekleşmeden önce icat edilmiştir.

  1. Bir init()fonksiyonun kullanımı. Bu biraz jQuery's gibi çalışır .ready(). Oluşturduğunuz nesne yalnızca kendi içinde initveya readyişlevinde kullanılabilir:

    Kullanımı:

    var myObj = new myClass();
    myObj.init(function() {
        // inside here you can use myObj
    });

    Uygulama:

    class myClass {
        constructor () {
    
        }
    
        init (callback) {
            // do something async and call the callback:
            callback.bind(this)();
        }
    }
  2. Bir inşaatçı kullanın. Bu javascript çok kullanılan görmedim ama bir nesne zaman uyumsuz olarak inşa edilmesi gerektiğinde bu Java daha yaygın çalışma etrafında biridir. Tabii ki, oluşturucu deseni çok karmaşık parametreler gerektiren bir nesne oluştururken kullanılır. Bu tam olarak asenkron inşaatçılar için kullanım durumudur. Fark, bir zaman uyumsuz oluşturucunun bir nesneyi değil, o nesnenin sözünü döndürmesidir:

    Kullanımı:

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

    Uygulama:

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

    Zaman uyumsuz / beklemede uygulama:

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

Not: Yukarıdaki örneklerde asenkron oluşturucu için vaatler kullanmamıza rağmen, bunlar kesinlikle gerekli değildir. Bir geri çağrıyı kabul eden bir oluşturucuyu da kolayca yazabilirsiniz.


Statik fonksiyonların içindeki fonksiyonların çağrılması ile ilgili not.

Bunun, zaman uyumsuz kurucularla hiçbir ilgisi yoktur, ancak anahtar kelimenin thisgerçekte ne anlama geldiğiyle (yöntem adlarının otomatik çözümlemesi yapan dillerden, yani thisanahtar kelimeye ihtiyaç duymayan dillerden gelen insanlar için biraz şaşırtıcı olabilir ).

thisKelime örneklenmiş nesneyi ifade eder. Sınıf değil. Bu nedenle this, statik işlev herhangi bir nesneye bağlı olmadığından, doğrudan sınıfa bağlı olduğu için normalde statik işlevlerin içinde kullanılamaz .

Yani, aşağıdaki kodda:

class A {
    static foo () {}
}

Yapamazsın:

var a = new A();
a.foo() // NOPE!!

bunun yerine şöyle çağırmanız gerekir:

A.foo();

Bu nedenle, aşağıdaki kod bir hataya neden olur:

class A {
    static foo () {
        this.bar(); // you are calling this as static
                    // so bar is undefinned
    }
    bar () {}
}

Düzeltmek için barnormal bir işlev veya statik bir yöntem yapabilirsiniz:

function bar1 () {}

class A {
    static foo () {
        bar1();   // this is OK
        A.bar2(); // this is OK
    }

    static bar2 () {}
}

yorumlara dayanarak, bunun genellikle bir el kitabı olmayan init()ancak srcveya href( veya bu durumda data-uid) gibi belirli bir özelliğe bağlı işlevselliğe sahip olan bir html öğesi olduğu fikrine dikkat edin. her yeni bir değer bağlandığında (ve muhtemelen inşaat sırasında da, ancak sonuçta ortaya çıkan kod yolunu beklemeden)
init'i bağlar ve başlatır

Aşağıdaki cevabın neden yetersiz olduğu hakkında yorum yapmalısınız (eğer öyleyse). Ya da başka şekilde ele alın.
Augie Gardner

bindİlk örnekte neden gerekli olduğunu merak ediyorum callback.bind(this)();? Böylece this.otherFunc()geri arama içinde gibi şeyler yapabilirsiniz ?
Alexander Craggs

1
@AlexanderCraggs Geri aramada sadece rahatlık thisanlamına gelir myClass. Her zaman myObjbunun yerine kullanırsanız thisihtiyacınız yoktur
slebetman

1
Şu anda dilde bir sınırlama var, ancak gelecekte neden const a = await new A()düzenli işlevlere ve asenkron işlevlere sahip olduğumuzu göremiyorum .
7ynk3r

138

Sen olabilir kesinlikle bunu. Temelde:

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

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

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

sınıf kullanımı oluşturmak için:

let instance = await new AsyncConstructor();

Bu çözümün birkaç kısa düşüşü var:

supernot : Kullanmanız gerekiyorsa super, zaman uyumsuz geri arama içinde çağıramazsınız.

TypeScript notu: yapıcı Promise<MyClass>yerine type döndürdüğü için bu, TypeScript ile ilgili sorunlara neden olur MyClass. Bildiğim bunu çözmenin kesin bir yolu yok. @Blitter tarafından önerilen potansiyel bir yol, kurucu gövdenin /** @type {any} */başlangıcına koymaktır , ancak bunun her durumda işe yarayıp yaramadığını bilmiyorum.


1
@PAStheLoD Ben dönüş olmadan nesneye çözecek sanmıyorum ancak bunu söylüyorum söylüyorum, bu yüzden spec gözden geçirmek ve güncelleme olacak ...
Downgoat

2
@JuanLanus async bloğu parametreleri otomatik olarak yakalayacaktır, bu nedenle x argümanı için tek yapmanız gerekenconstructor(x) { return (async()=>{await f(x); return this})() }
Downgoat

1
@PAStheLoD: return thisgereklidir, çünkü constructorbu sizin için otomatik olarak yapılırken , zaman uyumsuz IIFE bunu yapmaz ve sonunda boş bir nesne döndürürsünüz.
Dan Dascalescu

1
Şu anda TS 3.5.1 hedefleme ES5, ES2017, ES2018 (ve muhtemelen diğerleri, ama ben kontrol etmedim) bir yapıcıda bir dönüş yaparsanız şu hata iletisini alırsınız: "Yapıcı imzasının dönüş türü sınıfın örnek türü. " IIFE'nin türü bir Sözdür <bu> ve sınıf bir Söz <T> olmadığından, nasıl çalışabileceğini görmüyorum. (Bu 'dışında' ne döndürebilirsin?) Yani bu her iki getirinin de gereksiz olduğu anlamına gelir. (Derleme hatasına yol açtığı için dış
kısım

3
@PAStheLoD evet, bu bir daktilo sınırlaması. Tipik JS sınıf Tdönmelidir Tinşa zaman ama biz dönmek zaman uyumsuz yeteneğini elde etmek Promise<T>için hangi giderir this, ama kafasını karıştıran typescript söyledi. Dış dönüşe ihtiyacınız var, aksi takdirde vaatin ne zaman tamamlandığını bilemezsiniz - sonuç olarak bu yaklaşım TypeScript üzerinde çalışmaz (belki de tür takma adıyla bir miktar kesmek yoksa?) Bir daktilo uzmanı olsa da bununla konuşamıyor
Downgoat

7

Eşzamansız işlevler vaat edildiğinden, sınıfınızda sınıfın örneğini döndüren bir eşzamansız işlev yürüten statik bir işlev oluşturabilirsiniz:

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()Bir asenkron işlevinden ile çağrı yapın .


5

Yorumlarınıza dayanarak, muhtemelen varlık yüklemeli diğer HTMLElement öğelerinin ne yaptığını yapmalısınız: sonuca bağlı olarak bir yük veya hata olayı oluşturarak yapıcıyı bir yandan yükleme eylemi başlatmasını sağlayın.

Evet, bu sözleri kullanmak anlamına gelir, ama aynı zamanda "işleri her HTML öğesiyle aynı şekilde yapmak" anlamına gelir, bu yüzden iyi bir şirketdesiniz. Örneğin:

var img = new Image();
img.onload = function(evt) { ... }
img.addEventListener("load", evt => ... );
img.onerror = function(evt) { ... }
img.addEventListener("error", evt => ... );
img.src = "some url";

bu, kaynak varlığın, başarılı olduğunda, sona erdiğinde onloadve yanlış gittiğinde sona eren eşzamansız yükünü başlatır onerror. Yani, kendi sınıfınızı da yapın:

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

Ve sonra renderLoaded / renderError işlevlerini olay çağrıları ve shadow dom ile ilgilenirsiniz:

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

Ayrıca Seninkini değişti dikkat ida classsize bazı garip kod yazmak sürece sadece hiç tek bir örneği izin çünkü, <e-mail>bir sayfadaki eleman, benzersiz bir tanımlayıcı kullanmak ve daha sonra elemanların bir grup atamak mümkün değil.


2

Bu test senaryosunu @ Downgoat'ın cevabına dayanarak yaptım.
NodeJS üzerinde çalışır. Bu, zaman uyumsuz bölümün bir setTimeout()çağrı tarafından sağlandığı Downgoat kodudur .

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

Kullanım durumum, bir web uygulamasının sunucu tarafı için DAO'lardır.
DAO'ları gördüğüm gibi, her biri bir kayıt formatıyla ilişkili, benim durumumda örneğin bir aşçı gibi bir MongoDB koleksiyonu.
Bir cooksDAO örneği bir aşçının verilerini tutar.
Huzursuz zihnimde, aşçıyı argüman olarak sağlayan bir aşçının DAO'sunu başlatabilirdim ve örnekleme nesneyi yaratıp aşçının verileriyle doldururdu.
Böylece yapıcıya zaman uyumsuz şeyler çalıştırma ihtiyacı.
Yazmak istedim:

let cook = new cooksDAO( '12345' );  

gibi özelliklere sahip olmak cook.getDisplayName().
Bu çözüm ile yapmam gerekenler:

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

ideale çok benzer.
Ayrıca, bunu bir asyncişlev içinde yapmam gerekiyor .

B-planım, bir init işlevi kullanmak için @slebetman önerisine dayanarak veri yüklemesini yapıcıdan dışarıda bırakmak ve şöyle bir şey yapmaktı:

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

ki bu kurallara uymaz.


2

yapıda zaman uyumsuz yöntem kullan ???

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

Stopgap çözümü

Bir async init() {... return this;}yöntem oluşturabilir ve bunun yerine new MyClass().init()normalde ne zaman söyleyeceğinizi yapabilirsiniz new MyClass().

Bu temiz değildir, çünkü nesneyi her zaman böyle başlatmak için kodunuzu kullanan herkese ve kendinize güvenir. Ancak bu nesneyi kodunuzda yalnızca belirli bir yerde veya iki yerde kullanıyorsanız, belki de iyi olabilir.

Ancak ES'nin tip sistemi olmadığı için önemli bir sorun ortaya çıkıyor, bu yüzden çağırmayı unutursanız undefined, yapıcı hiçbir şey döndürmediği için geri döndünüz. Hata. Çok daha iyi bir şey yapmak olurdu:

Yapılacak en iyi şey:

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}

Fabrika yöntemi çözümü (biraz daha iyi)

Ancak, yanlışlıkla yeni AsyncOnlyObject yapabilirsiniz, muhtemelen Object.create(AsyncOnlyObject.prototype)doğrudan kullanan fabrika işlevini oluşturmanız gerekir :

async function newAsync_AsyncOnlyObject() {
    return await Object.create(AsyncOnlyObject.prototype).init();
}

newAsync_AsyncOnlyObject().then(console.log);
// output: AsyncOnlyObject {someField: 5}

Bununla birlikte, bu kalıbı birçok nesnede kullanmak istediğinizi söyleyin ... bunu bir dekoratör ya da (verbosely, ugh) gibi tanımladıktan sonra çağırdığınız bir şey olarak soyutlayabilirsiniz postProcess_makeAsyncInit(AsyncOnlyObject), ama burada kullanacağım extendsçünkü bir tür alt sınıf semantiğine uyuyor (alt sınıflar üst sınıf + ekstradır, çünkü üst sınıfın tasarım sözleşmesine uymaları ve ek şeyler yapmaları gerekir; üst öğe de zaman uyumsuz olmasaydı, zaman uyumsuz bir alt sınıf garip olurdu, çünkü aynı şekilde başlatılamazdı yön):


Soyutlanmış çözüm (genişletme / alt sınıf versiyonu)

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}

(üretimde kullanmayın: Anahtar kelime argümanları için bir sarıcı yazmanın doğru yolu olup olmadığı gibi karmaşık senaryolar üzerinde düşünmedim.)


2

Diğerlerinin söylediği gibi, çalışmasını sağlayabilirsiniz.

JavaScript classes, kelimenin tam anlamıyla constructorbaşka bir sınıfın bir örneği bile olabilir. Böylece, Promisesınıfınızın yapıcısından gerçek örneğine çözümleyen bir a döndürebilirsiniz .

Aşağıda bir örnek verilmiştir:

export class Foo {

    constructor() {

        return (async () => {

            // await anything you want

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

Ardından, Fooşu şekilde örnekler oluşturacaksınız :

const foo = await new Foo();

1

Eğer kaçınabiliyorsanız extend , sınıfları hep birlikte önleyebilir ve fonksiyon kompozisyonunu kurucu olarak kullanabilirsiniz . Sınıf üyeleri yerine kapsamdaki değişkenleri kullanabilirsiniz:

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

ve basit bir şekilde kullanın

const a = await buildA(...);

Daktilo veya akış kullanıyorsanız, kurucuların arayüzünü bile uygulayabilirsiniz

Interface A {
  getData: object;
}

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

0

Oluşturucu deseninde call () kullanarak varyasyon:

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

Hemen iletiyi döndüren ve ileti değişkenine ayarlayan anonim bir zaman uyumsuzluk işlevi çağırabilirsiniz. Bu kalıba aşina değilseniz hemen çağrılan işlev ifadelerine (IEFES) göz atmak isteyebilirsiniz. Bu bir cazibe gibi çalışacaktır.

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

-1

@ slebetmen'in kabul edilen cevabı bunun neden işe yaramadığını iyi açıklıyor. Bu yanıtta sunulan iki desene ek olarak, başka bir seçenek de async özelliklerine yalnızca özel bir async alıcısı aracılığıyla erişmektir. Yapıcı () daha sonra özelliklerin zaman uyumsuz oluşturulmasını tetikleyebilir, ancak alıcı daha sonra özelliği kullanmadan veya döndürmeden önce özelliğin kullanılabilir olup olmadığını kontrol eder.

Bu yaklaşım özellikle bir nesneyi başlangıçta bir kez başlatmak istediğinizde ve bunu bir modülün içinde yapmak istediğinizde kullanışlıdır. Örneğinizi başlatmak index.jsve örneği ihtiyaç duyulan yerlerde requiregeçirmek yerine, yalnızca global nesnenin gerekli olduğu her yerde modülünüz.

kullanım

const instance = new MyClass();
const prop = await instance.getMyProperty();

uygulama

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

Diğer cevaplar aşikar. Yapıcıdan async işlevini çağırmanız yeterlidir:

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

Gibi burada başka bir "bariz" cevabı , bu bir programcı genellikle yapıcı, yani nesne oluşturulduğunda içeriği ayarlandığını ne beklediğini yapmayacağım.
Dan Dascalescu

2
@DanDascalescu Sadece eşzamansız olarak ayarlanır, bu tam olarak sorgulayıcının istediği şeydir. Amacınız, nesne oluşturulduğunda içeriğin eşzamanlı olarak ayarlanmadığı, ki bu soru için gerekli değildir. Bu yüzden soru, bir kurucu içinde await / async kullanmakla ilgilidir. Bir yapıcıdan istediğiniz zaman bir async işlevini çağırarak istediğiniz kadar async / async'i nasıl çağırabileceğinizi gösterdim. Soruyu mükemmel cevapladım.
Navigateur

@Navigateur bu aynı çözüm oldu, ama başka bir benzer soruya yorum bu şekilde yapılmaması gerektiğini göstermektedir. Bir vaat olmak ana sorun yapıcı içinde kaybolur ve bu antipattern. Oluşturucunuzdan zaman uyumsuz işlev çağırmanın bu yaklaşımını önerdiği referanslarınız var mı?
Marklar

1
@Marklar referans yok, neden ihtiyacınız var? İlk etapta ihtiyacınız yoksa bir şeyin "kaybolması" önemli değil. Ve söze ihtiyacınız varsa, this.myPromise =(genel anlamda), bu nedenle, herhangi bir anlamda bir anti-desen eklemek önemsizdir . İnşaatta, dönüş değeri olmayan bir asenkron algoritmayı başlatmak için mükemmel geçerli durumlar vardır ve yine de bize basit bir şey ekler, bu yüzden bunu yapmamayı tavsiye eden bir şey yanlış anlıyor
Navigateur

1
Yanıtlamak için zaman ayırdığınız için teşekkür ederiz. Stackoverflow burada çelişkili cevaplar nedeniyle daha fazla okuma arıyordu. Bu senaryo için en iyi uygulamalardan bazılarını onaylamayı umuyordum.
Marklar

-2

thenÖrneğe işlev eklemelisiniz . otomatik Promiseolarak değiştirilebilir bir nesne olarak tanıyacaktırPromise.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)thishala yenilebilir olduğu gibi çalışmaz. Bu, hiç bitmeyen bir özyinelemeli çözüme yol açar.
Bergi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.