অ্যাসিঙ্ক / অ্যাওয়েট ক্লাস কনস্ট্রাক্টর


169

এই মুহুর্তে, আমি 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

এটিকে অবরুদ্ধ করার কোনও উপায় কি যাতে আমি এর মধ্যে async ব্যবহার করতে / অপেক্ষা করতে পারি? কলব্যাকের প্রয়োজনের পরিবর্তে বা .থেন ()?


6
একজন নির্মাণকারীর উদ্দেশ্য হ'ল আপনাকে কোনও জিনিস বরাদ্দ দেওয়া এবং তারপরে তত্ক্ষণাত্ ফিরে আসা return আপনি কেন আপনার নির্মাতা async হওয়া উচিত বলে ঠিক মনে করেন, সে সম্পর্কে আপনি আরও অনেক নির্দিষ্ট হতে পারেন ? কারণ আমরা এখানে একটি এক্সওয়াই সমস্যা মোকাবেলার প্রায় গ্যারান্টিযুক্ত ।
মাইক 'পোম্যাক্স' কামারম্যানস

4
@ মাইক'পোম্যাক্স 'কামারম্যানস এটি বেশ সম্ভব। মূলত, এই উপাদানটি লোড করার জন্য প্রয়োজনীয় মেটাডেটা পেতে আমার একটি ডাটাবেসকে জিজ্ঞাসা করতে হবে। ডাটাবেসটি জিজ্ঞাসা করা একটি অ্যাসিনক্রোনাস অপারেশন, এবং তাই উপাদানটি তৈরির আগে আমার এটির জন্য অপেক্ষা করার কিছু উপায় প্রয়োজন। আমি কলব্যাকগুলি ব্যবহার করব না, কারণ আমি প্রকল্পের বাকি অংশ জুড়ে অপেক্ষা / অ্যাসিঙ্ক ব্যবহার করেছি এবং ধারাবাহিকতা বজায় রাখতে চাই।
আলেকজান্ডার ক্র্যাগস

@ মাইক'পোম্যাক্স-কামারম্যানস এর সম্পূর্ণ প্রসঙ্গটি একটি ইমেল ক্লায়েন্ট, যেখানে প্রতিটি এইচটিএমএল উপাদান অনুরূপ দেখায় <e-mail data-uid="1028"></email>এবং সেখান থেকে customElements.define()পদ্ধতিটি ব্যবহার করে তথ্য সহ জনপ্রিয় হয় ।
আলেকজান্ডার ক্রেগস 21

আপনি বেশিরভাগই চান না কোনও কনস্ট্রাক্টর অ্যাসিঙ্ক হোক। একটি সিঙ্ক্রোনাস কনস্ট্রাক্টর তৈরি করুন যা আপনার অবজেক্টটিকে ফিরিয়ে দেয় এবং তারপরে .init()অ্যাসিঙ্ক স্টাফ করার মতো পদ্ধতি ব্যবহার করুন । এছাড়াও, যেহেতু আপনি এইচটিএমলেমেণ্টকে সাবলকস করেছেন, সম্ভবত এটি সম্ভবত সম্ভবত এই শ্রেণিটি ব্যবহার করে কোডটি কোনও অ্যাসিঙ্ক বিষয় নয় তাই আপনার সম্ভবত যে কোনওভাবে সম্পূর্ণ ভিন্ন সমাধানের সন্ধান করতে হবে extremely
jender00

উত্তর:


263

এটি কখনই কাজ করতে পারে না

asyncশব্দ পারবেন awaitএকটি ফাংশন হিসাবে চিহ্নিত ব্যবহৃত হবে asyncকিন্তু এটি একটি প্রতিশ্রুতি জেনারেটরের মধ্যে যে ফাংশন পরিবর্তন করে। সুতরাং চিহ্নিত একটি ফাংশন asyncএকটি প্রতিশ্রুতি ফিরে আসবে। অন্যদিকে একজন কনস্ট্রাক্টর এটি নির্মাণ করা বস্তুটি ফেরত দেয়। সুতরাং আমাদের এমন একটি পরিস্থিতি রয়েছে যেখানে আপনি কোনও জিনিস এবং প্রতিশ্রুতি উভয়ই ফিরিয়ে দিতে চান: একটি অসম্ভব পরিস্থিতি।

আপনি কেবলমাত্র async ব্যবহার করতে পারেন / অপেক্ষা করতে পারেন যেখানে আপনি প্রতিশ্রুতি ব্যবহার করতে পারেন কারণ তারা প্রতিশ্রুতিগুলির জন্য মূলত সিনট্যাক্স চিনি। আপনি কন্সট্রাক্টরে প্রতিশ্রুতি ব্যবহার করতে পারবেন না কারণ কোনও কনস্ট্রাক্টরকে অবশ্যই নির্মাণের জন্য বস্তুটি ফিরিয়ে দিতে হবে, প্রতিশ্রুতি নয়।

এটিকে কাটিয়ে উঠতে দুটি নকশার নিদর্শন রয়েছে, প্রতিশ্রুতি দেওয়ার আগেই দুটি আবিষ্কার হয়েছিল।

  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. একজন বিল্ডার ব্যবহার করুন। আমি জাভাস্ক্রিপ্টে এটি খুব বেশি ব্যবহার করে দেখিনি তবে জাভাতে এটি একটি সাধারণ কাজগুলির আশেপাশের একটি যখন যখন কোনও বস্তু অবিচ্ছিন্নভাবে নির্মাণ করা প্রয়োজন। অবশ্যই, বিল্ডার প্যাটার্নটি এমন কোনও বিষয় তৈরি করার জন্য ব্যবহৃত হয় যার জন্য অনেক জটিল পরামিতি প্রয়োজন। এটি হ'ল অ্যাসিনক্রোনাস বিল্ডারদের জন্য ব্যবহারের ক্ষেত্রে। পার্থক্যটি হ'ল একটি অ্যাসিঙ্ক বিল্ডার কোনও জিনিস ফেরত দেয় না তবে সেই বস্তুর প্রতিশ্রুতি দেয়:

    ব্যবহার:

    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 / অপেক্ষার সাথে বাস্তবায়ন:

    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) সাথে আবদ্ধ থাকে যার অর্থ একটি সেটার ব্যবহার করা হয় যা উভয়ই প্রতিবার যখন কোনও নতুন মান আবদ্ধ হয় তখন
থ্রিকে

নীচের উত্তরটি অপর্যাপ্ত কেন (যদি তা হয়) আপনার মন্তব্য করা উচিত। অথবা অন্যথায় এটি ঠিকানা।
অগি গার্ডনার 21 'এ 15

আমি আগ্রহী কেন bindপ্রথম উদাহরণে প্রয়োজন callback.bind(this)();? যাতে আপনি this.otherFunc()কলব্যাকের মধ্যে জিনিসগুলি করতে পারেন ?
আলেকজান্ডার ক্র্যাগস

1
@ আলেকজান্ডারক্র্যাগস এটি কেবল সুবিধার্থে যাতে কলব্যাকটি thisউল্লেখ করে myClass। আপনি যদি সর্বদা এর myObjপরিবর্তে আপনার ব্যবহার করেন তবে thisএটির দরকার নেই
স্লিটবেটম্যান

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এ্যাসিঙ্ক কলব্যাকের মধ্যে কল করতে পারবেন না।

টাইপস্ক্রিপ্ট নোট: এটি টাইপস্ক্রিপ্টের সাথে সমস্যা সৃষ্টি করে কারণ কনস্ট্রাক্টরের Promise<MyClass>পরিবর্তে প্রকারটি ফেরত দেয় MyClass। আমি জানি যে এটির সমাধানের কোনও সঠিক উপায় নেই। @ ব্লিটার দ্বারা প্রস্তাবিত একটি সম্ভাব্য উপায় হ'ল কনস্ট্রাক্টর বডির /** @type {any} */শুরুতে — আমি জানি না যদিও এটি সমস্ত পরিস্থিতিতে কাজ করে।


1
@ পাসথলড আমি মনে করি না যে এটি প্রত্যাবর্তন ছাড়াই বিষয়টির সমাধান করবে তবে আপনি বলছেন যে এটি এমনভাবে
ঘটবে

2
@ জুয়ানলানাস অ্যাসিঙ্ক ব্লক স্বয়ংক্রিয়ভাবে প্যারামিটারগুলি ক্যাপচার করবে তাই যুক্তি x এর জন্য আপনাকে কেবল constructor(x) { return (async()=>{await f(x); return this})() }
করণীয়

1
@ পাসথল্ড: return thisপ্রয়োজনীয়, কারণ constructorএটি আপনার জন্য স্বয়ংক্রিয়ভাবে করার সময়, যে অ্যাসিঙ্ক আইআইএফই না করে, এবং আপনি একটি খালি বস্তু ফিরে আসবেন।
ড্যান ড্যাসক্লেস্কু

1
বর্তমানে ES5, ES2017, ES2018 (এবং সম্ভবত অন্যরা, কিন্তু আমি চেক করি নি) হিসাবে টিএস 3.5.1 হিসাবে লক্ষ্য করে যদি আপনি কোনও কনস্ট্রাক্টরে রিটার্ন করেন তবে আপনি এই ত্রুটি বার্তাটি পান: "রিটার্ন ধরণের কনস্ট্রাক্টর স্বাক্ষরের জন্য অবশ্যই নিয়োগযোগ্য হতে হবে be ক্লাসের উদাহরণ টাইপ। " IIFE এর ধরণটি একটি প্রতিশ্রুতি <তম> এবং ক্লাসটি যেহেতু কোনও প্রতিশ্রুতি নয় <T> তাই এটি কীভাবে কাজ করতে পারে তা আমি দেখতে পাই না। (আপনি 'এটি' ব্যতীত আর কী ফিরিয়ে দিতে পারেন?) সুতরাং এর অর্থ উভয়ই রিটার্ন অপ্রয়োজনীয়। (
বাইরেরটি

3
@ পাসথলড হ্যাঁ, এটি টাইপস্ক্রিপ্টের সীমাবদ্ধতা। সাধারণত জেএস-তে কোনও ক্লাসের নির্মাণের সময় Tফিরে আসা উচিত Tতবে অ্যাসিঙ্কের দক্ষতা অর্জনের জন্য আমরা ফিরে আসি Promise<T>যা সমাধান করে thisতবে এটি টাইপস্ক্রিপ্টকে বিভ্রান্ত করে। আপনার বাহ্যিক রিটার্নের দরকার নেই অন্যথায় আপনি প্রতিশ্রুতি শেষ হওয়ার পরে জানতে পারবেন না a ফলস্বরূপ এই পদ্ধতিটি টাইপস্ক্রিপ্টে কাজ করবে না (যদি সম্ভবত টাইপ এলিয়াসিংয়ের কিছু হ্যাক না থাকে)? কোনও টাইপ
স্ক্রিপ্ট

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

আপনার মন্তব্যের উপর ভিত্তি করে, আপনার সম্ভবত সম্পদ লোডিং সহ প্রতিটি এইচটিএমলেমেন্ট যা করে তা করা উচিত: ফলাফলটির উপর নির্ভর করে কোনও লোড বা ত্রুটি ইভেন্ট উত্পন্ন করে কনস্ট্রাক্টর একটি পার্শ্বস্থায়ী ক্রিয়া শুরু করুন।

হ্যাঁ, এর অর্থ প্রতিশ্রুতি ব্যবহার করা, তবে এর অর্থ "জিনিসগুলি প্রতিটি অন্যান্য এইচটিএমএল উপাদানগুলির মতো একইভাবে করা", যাতে আপনি ভাল সঙ্গী হন। এই ক্ষেত্রে:

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(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একটি থেকে class, কারণ যদি না আপনি কিছু অদ্ভুত কোড লিখতে শুধুমাত্র কখনও আপনার একটি একক উদাহরণস্বরূপ অনুমতি <e-mail>কোনো পৃষ্ঠায় উপাদান, আপনি একটি অনন্য শনাক্তকারী ব্যবহার করে না এবং তারপর উপাদানের একটি গুচ্ছ তা নির্ধারণ করুন।


2

আমি @ ডাওনগোটের উত্তরের ভিত্তিতে এই পরীক্ষার কেসটি তৈরি করেছি।
এটি নোডজেএসে চলে। এটি ডাউঙ্গোটের কোড যেখানে অ্যাসিঙ্ক অংশটি 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 );

আমার ব্যবহারের ক্ষেত্রটি একটি ওয়েব অ্যাপ্লিকেশনটির সার্ভার-সাইডের জন্য ডিএওস।
আমি ডিএওগুলিকে দেখতে পাচ্ছি, তারা প্রত্যেকেই রেকর্ড ফর্ম্যাটের সাথে যুক্ত, আমার ক্ষেত্রে উদাহরণস্বরূপ একটি কুকের মতো একটি মঙ্গোডিবি সংগ্রহ।
একটি কুক্সএডিও উদাহরণ একটি কুকের ডেটা ধরে।
আমার অস্থির মনে আমি কোনও রান্নার ডিএও তাত্ক্ষণিকভাবে যুক্তি হিসাবে কুকআইড সরবরাহ করতে সক্ষম হব এবং তাত্ক্ষণিকতাটি বস্তুটি তৈরি করবে এবং এটি কুকের ডেটা দিয়ে তৈরি করবে।
সুতরাং কনস্ট্রাক্টরের মধ্যে অ্যাসিঙ্ক স্টাফ চালানো দরকার।
আমি লিখতে চেয়েছিলাম:

let cook = new cooksDAO( '12345' );  

যেমন উপলব্ধ বৈশিষ্ট্য আছে cook.getDisplayName()
এই সমাধানটি দিয়ে আমাকে করতে হবে:

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

যা আদর্শের সাথে খুব মিল।
এছাড়াও, আমি একটি asyncফাংশন ভিতরে এটি করা প্রয়োজন ।

আমার বি-পরিকল্পনাটি ছিল ডিজিটাল ফাংশনটি ব্যবহার করার জন্য @ স্লেবটম্যানের পরামর্শের ভিত্তিতে ডেটা লোডিংটি কনস্ট্রাক্টরের বাইরে রেখে, এবং এই জাতীয় কিছু করা:

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

এটি পরিষ্কার নয় কারণ এটি আপনার কোডটি এবং প্রত্যেককে নিজের মতো করে ব্যবহার করে এমন কিছুর উপর নির্ভর করে যা সর্বদা এই জাতীয় জিনিসটি ইনস্ট্যান্ট করে। তবে আপনি যদি কেবল এই কোডটি কোনও নির্দিষ্ট জায়গায় বা আপনার কোডের দু'টিতে ব্যবহার করছেন তবে এটি ভাল হতে পারে।

যদিও একটি উল্লেখযোগ্য সমস্যা দেখা দেয় কারণ ইএসের কোনও টাইপ সিস্টেম নেই, তাই আপনি যদি এটি কল করতে ভুলে যান তবে আপনি কেবল ফিরে এসেছেন 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কারণ এটি সাবক্লাস শব্দার্থবিজ্ঞানের মধ্যে সাজানো যায় না (সাবক্লাসগুলি প্যারেন্ট ক্লাস + অতিরিক্ত, এতে তাদের পিতামাত্ত শ্রেণীর নকশা চুক্তি মেনে চলা উচিত এবং অতিরিক্ত জিনিসও করা যেতে পারে; পিতা-মাতাও অ্যাসিঙ্ক না থাকলে একটি অ্যাসিঙ্ক সাবক্লাস বিস্ময়কর হবে, কারণ এটি একইরূপে আরম্ভ করা যায়নি because পথ):


বিমূর্ত সমাধান (প্রসারিত / সাবক্লাস সংস্করণ)

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

অন্যরা যেমন বলেছে তার বিপরীতে, আপনি এটি কাজে লাগাতে পারেন।

জাভাস্ক্রিপ্ট classএসগুলি তাদের থেকে 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(...);

আপনি টাইপ করা বিষয় বা প্রবাহ ব্যবহার করেন, তাহলে আপনি এমনকি ইন্টারফেস জোরদার করতে কনস্ট্রাকটর

Interface A {
  getData: object;
}

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

0

কল () ব্যবহার করে বিল্ডার প্যাটার্নে পার্থক্য:

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

আপনি তাত্ক্ষণিকভাবে একটি বেনামে অ্যাসিঙ্ক ফাংশন শুরু করতে পারেন যা বার্তাটি ফেরত দেয় এবং বার্তা পরিবর্তনশীলটিতে সেট করে। আপনি যদি এই প্যাটার্নটির সাথে অপরিচিত হন তবে আপনি অবিলম্বে অনুরোধ করা ফাংশন এক্সপ্রেশন (আইআইএফইএস) একবার দেখে নিতে চাইতে পারেন। এটি একটি কবজির মতো কাজ করবে।

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

-1

@ স্বেচ্ছাসেবীদের গৃহীত উত্তরগুলি কেন এটি কাজ করে না তা ভালভাবে ব্যাখ্যা করে। এই উত্তরে উপস্থাপিত দুটি নিদর্শন ছাড়াও, অন্য একটি বিকল্প হ'ল কেবলমাত্র কাস্টম অ্যাসিঙ্ক প্রাপ্তির মাধ্যমে আপনার অ্যাসিঙ্ক বৈশিষ্ট্যগুলি অ্যাক্সেস করা। কনস্ট্রাক্টর তারপরে বৈশিষ্ট্যগুলির async তৈরি করতে ট্রিগার করতে পারে, তবে প্রদত্ত ব্যক্তি এটি ব্যবহার করে বা ফেরত দেওয়ার আগে সম্পত্তিটি উপলব্ধ কিনা তা পরীক্ষা করে দেখুন।

আপনি যখন স্টার্টআপে একবার বিশ্বব্যাপী অবজেক্টটি শুরু করতে চান এবং আপনি এটি একটি মডিউলের অভ্যন্তরে করতে চান তখন এই পদ্ধতিরটি বিশেষভাবে কার্যকর। আপনার আরম্ভ করার পরিবর্তে 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>
    `
}

এখানে অন্য "সুস্পষ্ট" উত্তরের মতো , এটি প্রোগ্রামার সাধারণত কোনও কনস্ট্রাক্টরের প্রত্যাশা করে না, অর্থাৎ বস্তুটি তৈরি হওয়ার সময় সামগ্রীটি সেট করা থাকে।
ড্যান ড্যাসক্লেস্কু

2
@ ড্যানডাসক্লেস্কু এটি ঠিক অযৌক্তিকভাবে সেট করা হয়েছে, যা ঠিক প্রশ্নকর্তাকে প্রয়োজন। আপনার বক্তব্যটি হ'ল বিষয়বস্তুটি সিঙ্ক্রোনসিলে সেট করা হয় না যখন বস্তুটি তৈরি করা হয়, যা প্রশ্নের প্রয়োজন হয় না। এই কারণেই প্রশ্নটি কোনও কনস্ট্রাক্টরের কাছ থেকে অপেক্ষা / অ্যাসিঙ্ক ব্যবহার করার বিষয়ে। আমি দেখিয়েছি যে আপনি কোনও কনস্ট্রাক্টরের কাছ থেকে যতটা প্রত্যাশা / অ্যাসিঙ্ক চান তেমনভাবে এটি থেকে একটি অ্যাসিঙ্ক ফাংশন কল করে আপনি কীভাবে আবেদন করতে পারেন। আমি প্রশ্নের পুরো উত্তর দিয়েছি।
নেভিগেটর

@ নাভিগেটর একই সমাধানটি আমি নিয়ে এসেছি, তবে অন্য অনুরূপ প্রশ্নের মন্তব্যে বোঝানো হয়েছে যে এটি এভাবে করা উচিত নয়। প্রতিশ্রুতিবদ্ধ হওয়ার প্রধান সমস্যাটি কনস্ট্রাক্টরে হারিয়ে গেছে এবং এটি অ্যান্টিপ্যাটার্ন। আপনার কনস্ট্রাক্টরের কাছ থেকে অ্যাসিঙ্ক ফাংশন কল করার এই পদ্ধতির প্রস্তাব দেওয়ার ক্ষেত্রে আপনার কি কোনও রেফারেন্স রয়েছে?
মার্কার 0

1
@ মার্কলার কোন রেফারেন্স নেই, কেন আপনার কোনও দরকার? আপনার যদি প্রথমে এটির প্রয়োজন না হয় তবে কিছু "হারিয়ে গেছে" তা বিবেচনা করে না। এবং যদি আপনার প্রতিশ্রুতির দরকার হয় তবে এটি যুক্ত করতে তুচ্ছ this.myPromise =(সাধারণ অর্থে) সুতরাং কোনও দিক থেকে এটি কোনও বিরোধী নিদর্শন নয়। নির্মাণের পরে অ্যাসিঙ্ক অ্যালগরিদমটি বন্ধ করার প্রয়োজনের জন্য পুরোপুরি বৈধ মামলা রয়েছে, যার কোনও রিটার্নের মূল্য নেই এবং যেভাবেই আমাদের একজনকে যুক্ত করা যায়, সুতরাং যে কেউ এটি না করার পরামর্শ দিচ্ছে সে কিছু ভুল বোঝাবুঝি করছে
নেভিগেটর

1
উত্তর দেওয়ার জন্য সময় দেওয়ার জন্য ধন্যবাদ। স্ট্যাকওভারফ্লোতে এখানে বিরোধী উত্তরগুলির কারণে আমি আরও পড়ার জন্য খুঁজছিলাম। আমি এই দৃশ্যের জন্য সেরা কয়েকটি অনুশীলন নিশ্চিত করার আশা করছিলাম।
মার্কার

-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এখনও কাজযোগ্য হিসাবে কাজ করবে না । এটি কখনই শেষ না হওয়া পুনরাবৃত্তির সমাধানের দিকে নিয়ে যায়।
বার্গি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.