Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 异步/等待类构造函数_Javascript_Node.js_Async Await - Fatal编程技术网

Javascript 异步/等待类构造函数

Javascript 异步/等待类构造函数,javascript,node.js,async-await,Javascript,Node.js,Async Await,目前,我正在尝试在类构造函数中使用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) co

目前,我正在尝试在类构造函数中使用
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>
    `
  }
})

有没有一种方法可以避免这种情况,这样我就可以在其中使用async/Wait?不需要回调或.then()?

这可能永远不会起作用

async
关键字允许在标记为
async
的函数中使用
wait
,但它也将该函数转换为承诺生成器。因此,标记为
async
的函数将返回一个承诺。另一方面,构造函数返回它正在构造的对象。因此,我们有一种情况,你想返回一个对象和一个承诺:一种不可能的情况

您只能在可以使用承诺的地方使用async/await,因为它们本质上是承诺的语法糖。不能在构造函数中使用承诺,因为构造函数必须返回要构造的对象,而不是承诺

有两种设计模式可以克服这一点,它们都是在承诺出现之前发明的

  • 使用
    init()
    函数。这有点像jQuery的
    .ready()
    。您创建的对象只能在其自己的
    init
    ready
    函数中使用:

    用法:

    var myObj = new myClass();
    myObj.init(function() {
        // inside here you can use myObj
    });
    
    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 () {
    
        }
    
        init (callback) {
            // do something async and call the callback:
            callback.bind(this)();
        }
    }
    
    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);
               });
        }
    }
    
  • 使用生成器。我在javascript中没有看到过很多这种用法,但当对象需要异步构造时,这是Java中更常见的解决方法之一。当然,构建需要大量复杂参数的对象时,会使用生成器模式。这正是异步构建器的用例。不同之处在于,异步构建器不返回对象,而是返回该对象的承诺:

    用法:

    var myObj = new myClass();
    myObj.init(function() {
        // inside here you can use myObj
    });
    
    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 () {
    
        }
    
        init (callback) {
            // do something async and call the callback:
            callback.bind(this)();
        }
    }
    
    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
    ,因为静态函数没有绑定到任何对象,而是直接绑定到类

    也就是说,在以下代码中:

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

    根据您的评论,您可能应该像其他HtmleElement在资产加载时所做的那样:让构造函数启动一个侧加载操作,根据结果生成一个加载或错误事件

    是的,这意味着使用承诺,但它也意味着“以与其他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函数处理事件调用和阴影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', ...));
      }
    
    renderload(消息){
    const shadowRoot=this.attachShadow({mode:'open'});
    shadowRoot.innerHTML=`
    出现了一封随机电子邮件。${message}
    `;
    //有古代的事件监听器吗?
    如果(此.onload){
    这个.onload(…);
    }
    //可能存在现代事件侦听器。请发送事件。
    dispatchEvent(新事件('load',…);
    }
    renderFailed(){
    const shadowRoot=this.attachShadow({mode:'open'});
    shadowRoot.innerHTML=`
    没有电子邮件。
    `;
    //有古代的事件监听器吗?
    如果(此.onload){
    这是一个错误(…);
    }
    //可能存在现代事件侦听器。请发送事件。
    dispatchEvent(新事件('error',…);
    }
    

    还要注意的是,我将您的
    id
    更改为
    类,因为除非您编写一些奇怪的代码,在页面上只允许
    元素的单个实例,否则您不能使用唯一标识符,然后将其分配给一组元素。

    您应该向实例添加
    然后
    函数
    Promise
    将使用
    Promise将其识别为可启用对象。自动解析

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

    其他答案忽略了显而易见的问题。只需从构造函数中调用异步函数:

    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>
        `
    }
    
    constructor(){
    setContentAsync();
    }
    异步setContentAsync(){
    让uid=this.getAttribute('data-uid'))
    让消息=等待抓取uid(uid)
    const shadowRoot=this.attachShadow({mode:'open'})
    shadowRoot.innerHTML=`
    出现了一封随机电子邮件。${message}
    `
    }
    
    生成器模式的变体,使用call():


    因为异步函数是承诺,所以可以在类上创建一个静态函数,该函数执行一个异步函数,该函数返回类的实例:

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

    通过异步函数调用
    让yql=wait yql.init()

    您肯定可以这样做。基本上:

    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注意:这会导致TypeScript出现问题,因为构造函数返回type
    Promise'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' );  
    
    let cook = await new cooksDAO( '12345' );  
    
    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());
        });
    }
    
    Interface A {
      getData: object;
    }
    
    async function buildA0(...): Promise<A> { ... }
    async function buildA1(...): Promise<A> { ... }
    ...
    
    var message = (async function() { return await grabUID(uid) })()
    
    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}
    
    async function newAsync_AsyncOnlyObject() {
        return await Object.create(AsyncOnlyObject.prototype).init();
    }
    
    newAsync_AsyncOnlyObject().then(console.log);
    // output: AsyncOnlyObject {someField: 5}
    
    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}
    
    export class Foo {
    
        constructor() {
    
            return (async () => {
    
                // await anything you want
    
                return this; // Return the newly-created instance
            })();
        }
    }
    
    const foo = await new Foo();
    
    class Foo {
      private promiseReady;
    
      constructor() {
        this.promiseReady = this.init();
      }
    
      private async init() {
        await someAsyncStuff();
      }
    
      public ready() {
        return this.promiseReady;
      }
    }
    
    let foo = new Foo();
    foo.ready().then(() =>{
      // It's ready
    });
    
    let foo= new Foo();
    await foo.ready();