it-swarm.com.ru

ES6 асинхронный/ожидание в классах

Я пытаюсь создать класс, который будет отправлять пост-запрос (логин), сохранять куки-файл и использовать этот куки-файл для других операций, таких как загрузка файла.

Я создал локальный сервер, который получит метод post http с именем пользователя и паролем и маршрутизатор с именем /download, доступ к которому будет возможен только при входе пользователя, в противном случае он вернет you need to log in.

Проблема: Это прототип моего класса (перед рукой):

const request = require('request-promise-native')

class ImageDownloader {
  constructor(username = null, password = null) {
    this.username = username
    this.password = password
    this.cookie = request.jar()

    this.init()
  }

  init() {
    // login and get the cookie
  }

  download() {
    // needs the cookie
  }

  query() {
    // needs the cookie
  }
}

Как вы можете видеть из приведенного выше кода, мне нужен файл cookie для двух операций: download и query, поэтому я подумал о создании метода init, который будет выполнять начальные операции, такие как login, и вызывать его прямо в конструкторе, чтобы он был инициализирован и поместите cookie в переменную this.cookie для использования везде, но он не работает, кажется, что init вызывается после каждого другого метода.

const request = require('request-promise-native')

class ImageDownloader {
  constructor(username = null, password = null) {
    this.username = username
    this.password = password
    this.cookie = request.jar()

    this.init()
  }

  async init() {
    await request({
      uri: 'http://localhost/login',
      jar: this.cookie,
      method: 'post',
      formData: {
        'username': 'admin',
        'password': 'admin'
      }
    }).catch(e => console.error(e))
  }

  async download() {
    await request({
      uri: 'http://localhost/download/image.jpg',
      jar: this.cookie
    })
    .then(b => console.log(b))
    .catch(e => console.error(e))
  }

  query() {
    // ...
  }
}

const downloader = new ImageDownloader
downloader.download()

Мне возвращается, что мне нужно войти (ответ сервера) ... НО это работает, если я сделаю это изменение:

async download() {
  await init() // <<<<<<<<<<<<
  await request({
    uri: 'http://localhost/download/image.jpg',
    jar: this.cookie
  })
  .then(b => console.log(b))
  .catch(e => console.error(e))
}

Это работает, только если я вызываю init в методе download.

Если я помещаю console.log(this.cookie) в download, он возвращает пустую CookieJar, а если я помещаю то же самое в init, он возвращает правильный файл cookie, но он появляетсяПОСЛЕвыполнения загрузки, даже если я вызвал его в конструкторе перед вызовом download ,.

Как это решить? Большое спасибо.

@Правка

Я сделал изменения, которые @ agm1984 и @Jaromanda X сказал мне, но это все равно не работает :(

const request = require('request-promise-native')

class ImageDownloader {
  constructor(username = null, password = null) {
    this.username = username
    this.password = password
    this.cookie = request.jar()

    this.init().catch(e => console.error(e))
  }

  async init() {
    return await request({
      uri: 'http://localhost/login',
      jar: this.cookie,
      method: 'post',
      formData: {
        'username': 'admin',
        'password': 'admin'
      }
    })
  }

  async download() {
    return await request({
      uri: 'http://localhost/download/image.jpg',
      jar: this.cookie
    })
  }

  query() {
    // ...
  }
}

const downloader = new ImageDownloader
downloader.download()
          .then(b => console.log(b))
          .catch(e => console.error(e))

Но опять же ... это не сработает, если я не вызову init внутри download.

8
vajehu

Проблема в том, что init является асинхронным. Используя это так:

const downloader = new ImageDownloader;
downloader.download();

Функция download выполняется, пока init еще не завершена.

Я бы не стал вызывать метод init в конструкторе. Что бы я сделал, это что-то вроде этого:

1 - удалить вызов init из конструктора.
2- используйте класс так:

const downloader = new ImageDownloader();
downloader.init()
  .then(() => downloader.download());

и если вы вызываете init в функции async, вы можете сделать:

await downloader.init();
const result = await downloader.download();
1
Omar