ES6承诺和类属性

时间:2019-03-17 17:54:25

标签: javascript ecmascript-6 es6-promise es6-class

作为一名业余PHP程序员,我很难掌握JS异步行为。我正在编写一个Firefox WebExtension,它使用来自Storage API的两个StorageAreas来设置/获取选项,并且我想将所有选项合并到一个对象中以有效地传递应用程序:

'use strict';
class Options {

  constructor() {
    this.defaults = {};
    this.locals = {};
    this.options = {};
  }

  getDefaults() {
    browser.storage.managed.get().then(res => {
      this.defaults = res;
    });
  }

  getLocals() {
    browser.storage.local.get().then(res => {
      this.locals = res;
    });
  }

  get() {
    this.getDefaults();
    this.getLocals();
    this.options = Object.assign(this.defaults, this.locals); // <-- This is where the code fails: this.defaults and this.locals are empty.
    return this;
  }
}

const opts = new Options().get();
console.log(opts); // Object { defaults: {}, locals: {}, options: {} } background.js:31:1
console.log(Object.keys(opts)); // Array(3) [ "defaults", "locals", "options" ] background.js:32:1
console.log(opts.defaults); // Object {  } background.js:33:1

const options = Object.assign(opts.defaults, opts.locals);
console.log(options); // Object {  } background.js:36:1

我已经指出了错误首先触发的那一行,现在我的头撞到同一堵墙超过2天,我相信这与Firefox浏览器返回的Promise异步字符有关。*。 .get(),或与变量范围相关。

我尝试过:

  1. 在get *函数中声明局部变量(让= = this;)
  2. 在get *函数中使用async / await
  3. 将get * -functions结果绑定到this或this.defaults
  4. 在创建此类之前,我从嵌套Promises开始,但是后来我还是没有成功创建(全局)'options'变量。

感谢所有指针-我的主意是厌倦了查看/重写这36个位置...

2 个答案:

答案 0 :(得分:1)

您不必等待呼叫this.getDefaults();this.getLocals();所创建的承诺,因此在您进行this.options = Object.assign( ...时,数据尚未准备就绪。

如果在函数中创建一个Promise,则需要从中返回,以便调用者可以等待该Promise解决。

getDefaults() {
  return browser.storage.managed.get().then(res => {
    this.defaults = res;
  });
}

getLocals() {
  return browser.storage.local.get().then(res => {
    this.locals = res;
  });
}

get() {
    return Promise.all([
      this.getDefaults(),
      this.getLocals()
    ])
    .then(() => {
       this.options = Object.assign(this.defaults, this.locals);
       return this
    })
})

您当然还需要在then上使用awaitget()来等待get完成。

答案 1 :(得分:0)

Don't write asynchronous functions to initialise your instances。相反,在构造对象之前 进行异步工作,让构造函数将数据作为参数。

就您而言,就是

class Options {
  constructor(defaults = {}, locals = {}) {
    this.defaults = defaults;
    this.locals = locals;
    this.options = Object.assign(this.defaults, this.locals);
  }

  // static methods that don't modify an instance, but return promises
  static getDefaults() {
    return browser.storage.managed.get();
  }
  static getLocals() {
    return browser.storage.local.get();
  }

  // static method to load data and create an instance, returning a promise for it
  static async get() {
    const [defaults, locals] = await Promise.all([this.getDefaults(), this.getLocals()]);
    return new this(defaults, locals);;
  }
}

const options = Options.get();
console.log(options); // Promise {  }
options.then(opts => {
  console.log(opts); // Options { defaults: {…}, locals: {…}, options: {…} }
  console.log(Object.keys(opts)); // Array(3) [ "defaults", "locals", "options" ]
  console.log(opts.defaults); // Object { … }
});