代码之家  ›  专栏  ›  技术社区  ›  Sam

带承诺的构造函数中的同步代码[重复]

  •  1
  • Sam  · 技术社区  · 8 年前

    我在Node中做一个项目,我对Node语言不太熟悉。

    在这个项目中,我有一个类负责将数据读写到一个数据库——在本例中是LevelDB。理想情况下,我希望在构造函数中同步设置数据库连接,以便方法(writeitetem、readItem等)在调用过快时不会失败。或者换句话说,我不希望构造函数返回并允许下一行代码运行,直到实现所有承诺。

    我想我要么是遗漏了一些基本的语言,要么是在node中有一些我不知道的设计模式。一个同样失败的玩具例子如下:

    class AClass {
      constructor(n) {
        this.name = n;
        console.log('calling init.');
        this.init();
        console.log('init returned.');
      }
    
      func() {
        return new Promise(resolve =>  {
          setTimeout(() => {
            resolve(true);
          }, 2000);
        }); 
      }
    
      async init() {
        console.log('calling func()');
        let x = await this.func();
        console.log('after func(): ');
      }
    
    }
    
    
    let x = new AClass('test');
    console.log(JSON.stringify(x));
    

    这将产生输出:

    calling init.
    calling func()
    init returned.
    {"name":"test"}
    after func():
    

    这让我很惊讶。我本以为:

    calling init.
    calling func()
    after func():
    init returned.
    {"name":"test"}
    

    let storage = new StorageObject();
    storage.addItem(key, value);   // <-- this fails unless StorageObject
                                   //     finishes the db setup.
    

    谢谢! 山姆

    3 回复  |  直到 8 年前
        1
  •  3
  •   Mark    8 年前

    在连接之前不返回实例的目标将不起作用(至少不是这样)。构造函数的工作是创建一个实例并返回该实例。函数需要返回 同步地。如果它正在执行某个异步操作,则函数可以返回一个promise,但您不希望从需要实例的构造函数中得到promise。

    简单的方法是要求在创建对象之后对其进行初始化,然后构造函数可以构造并返回实例和 init

    class AClass {
      constructor(n) {/* some setup */}
    
      func() {
        return new Promise(resolve =>  {
          setTimeout(() => {
            resolve("some name");
          }, 1000);
        }); 
      }
    
      async init() {
        this.name = await this.func();
        return this
      }
    
    }
    
    new AClass('test').init()
    .then((initialized_obj) => console.log(initialized_obj))

    如果在node中执行此操作,还可以在初始化实例时使用eventEmitters发出事件。类似于:

    const EventEmitter = require('events');
    
    class AClass extends EventEmitter{
      constructor(n) {
        super()
        this.init()
        .then(() => this.emit("initialized"))
      }
    
      func() {
        return new Promise(resolve =>  {
          setTimeout(() => {
            resolve("some name");
          }, 1000);
        }); 
      }
    
      async init() {
        this.name = await this.func();
        return this
      }
    
    }
    
    let x = new AClass('test')
    x.on('initialized', () => console.log(x.name))
    
        2
  •  0
  •   Sandeep Gupta    8 年前

    关于你的代码有两件事:

    1. this.init() ),它将正常执行返回的await语句,并返回一个promise,控件将转到下一行( console.log('init returned.') ). 理解这一点会解决你的困惑。
    2. 等待语句后的代码( console.log('after func(): ');

    我已经重新调整了你的代码用途来做你想做的事。

        async function AClass(n) {
            let obj = {}
            obj.func = () => {
                return new Promise(resolve => {
                    setTimeout(() => {
                        resolve(true);
                    }, 2000);
                });
            };
        
            obj.init = async function () {
                console.log('calling func()');
                let x = await obj.func();
                console.log('after func(): ');
            };
        
            obj.name = n;
            console.log('calling init.');
            await obj.init();
            console.log('init returned.');
            return obj;
        
        }
        
        
        let x = AClass('test');
        x.then((resolveValue) => {
            /*
            *Now the "class" has been instantiated, 
            * code to use the object of the "class" goes here
            * */
            console.log(JSON.stringify(resolveValue));
        });
        3
  •  0
  •   David Knipe    8 年前

    AClass 同步地,您可以通过稍微重写代码的其他部分来完成。我假设这些方法 writeItem , readItem

    例如,假设您的类如下所示:

    class AClass {
      constructor(n) {
        this.name = n;
        this.init();
      }
    
      async init() {
        ...
      }
    
      async writeItem(item) {
        return await db.writeItem(item);
      }
    
      async readItem(itemId) {
        return await db.readItem(itemId);
      }
    
    }
    

    然后,您应该能够重写如下:

    class AClass {
      constructor(n) {
        this.name = n;
        this.awaitInit = this.init();
      }
    
      async init() {
        ...
      }
    
      async writeItem(item) {
        await this.awaitInit;
        return await db.writeItem(item);
      }
    
      async readItem(itemId) {
        await this.awaitInit;
        return await db.readItem(itemId);
      }
    
    }