@vshvydky

Как можно реализовать в JS ожидание исполнения асинхронных задач при описании класса?

Всем доброго дня.
Вопрос в следующем, как вы бы решили задачу с конструктором и асинхронными процессами.
Пример:
class Name {
     let self = this;
    constructor(data){
        this._init(data)
               .then(data=>{
                    self.init = data;
                    })
               .catch(console.error);
        }
    _init(data) { 
        return new Promise((resolve, reject) => {
            // искусственно создаем задержку, эмцлируя веб запрос:
            setTimeout(resolve, 2000, data);
            //resolve(data);
        })
     run(data) {
          rerurn data / this.init.
     }
    run2(data){
           let self = this;
           return new Promise((resolve, reject) => {
            resolve(data / self.init);
        })
     }
}

В примере выше мы при инициализации делаем асинхронную задачу, предположим что она будет занимать какое-то время (запрос по http или чего , не суть)
Как пример:
let name = new Name(2);
console.log(name.run(6));
//или
name.run2(6).then(console.log).catch(console.error);

Ожидаем получить 3, но можем и не получить, так как this.init может быть еще не получено и конструктор еще работает.
Кто как с этим борется?
У меня на ум, да и в практике реализован костыль, переменная - триггер, которая символизирует, что конструктор отработал и если триггер не установлен, делается задержка, но мне не нравится такой подход, может кто подскажет более изящное решение?

Пока нашел следующие решения:
1. Через фабрику:
class Engine {
    constructor(data) {
        this.data = data;
    }

    static makeEngine(pathToData) {
        return new Promise((resolve, reject) => {
            getData(pathToData).then(data => {
              resolve(new Engine(data))
            }).catch(reject);
        };
    }
}

Плюсом вижу, что объект будет создан только тогда, когда выполнится вся вермешляндия, минусом то, что объект будет результатом промиса и опять либо в генераторе работать с ним для удобства, либо в async. Ну или при жестком троллинге всего этого добра писать основной код почле тааймаута.

2. Через специфичный конструктор , мне идея понравилась, но надо потестировать, плюс использовать 7 ноду с хармони:
class Engine {

  constructor(path) {
    this.initialization = (async () => {
      this.resultOfAsyncOp = await doSomethingAsync(path)
    })()
  }

  async showPostsOnPage() {
    await this.initialization
    // actual body of the method
  }

}
  • Вопрос задан
  • 369 просмотров
Решения вопроса 1
@vshvydky Автор вопроса
Сам спросил, сам ответил....

прием любопытный, но не лишен вопросов, стоит ли так делать. Есть критика использования конструктора для выполнения методов инициализации. Но с асинхронными задачами мне показалось это приемлемым.

Открыт для новых идей.

class Name {

    constructor(data) {
        console.log('constructor start');
        this.initialization = (async () => {
            this.init = await this._init(data)
        })();
        console.log('constructor end');
    }
    _init(data){
        return new Promise((resolve, reject)=>{
            console.log('_init');
            setTimeout(resolve, 2000, data);
        });
    }

    async run(data) {
        console.log('run start');
        await this.initialization;
        console.log('run end');
        return data / this.init;
    }
}

let name = new Name(2);
name.run(6).then(console.log).catch(console.error);


Результат работы:

>node --harmony test2
constructor start
_init
constructor end
run start
run end
3
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы