ES6承诺和类属性

问题描述 投票:1回答:2

作为业余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的browser.storage返回的Promise的异步字符有关。*。get( ),或与变量范围有关。

我试过了:

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

任何指针的thx - 我的思绪已经厌倦了审查/重写这36个位置......

javascript ecmascript-6 es6-promise es6-class
2个回答
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完成。


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 { … }
});
© www.soinside.com 2019 - 2024. All rights reserved.