web-dev-qa-db-fra.com

ES6 async/wait dans les classes

J'essaie de créer une classe qui enverra une demande de publication (connexion), sauvegardera le cookie et l'utilisera pour d'autres opérations telles que le téléchargement d'un fichier.

J'ai créé un serveur local qui recevra une méthode post-http avec l'utilisateur et le mot de passe et un routeur appelé /download qui ne sera accessible que si l'utilisateur est connecté. Sinon, il retournera you need to log in.

Le problème: Ceci est le prototype de ma classe (avant la main):

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
  }
}

Comme vous pouvez le voir dans le code ci-dessus, j'ai besoin du cookie pour deux opérations, à savoir download et query, donc je pensais créer une méthode init qui exécutera les opérations initiales telles que login et l'appellera directement dans le constructeur afin qu'elle soit initialisée et stockée. placez le cookie sur la variable this.cookie à utiliser partout, mais cela ne fonctionne pas, il semble que init soit appelé après chaque autre méthode.

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()

_ {Il me revient que je dois me connecter (réponse du serveur)} ..... MAIS ça marche si je fais ce changement:

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))
}

Cela ne fonctionne que si j'appelle init dans la méthode download.

Si je mets console.log(this.cookie) dans download, il retourne un CookieJar et si je mets la même chose dans init, il retournera le cookie correct, mais il apparaît APR&EGRAVE;S l'exécution du téléchargement même si je l'ai appelé auparavant appelant download.

Comment résoudre ça? Merci beaucoup.

@modifier

J'ai apporté les modifications que @ agm1984 et @Jaromanda X m'ont dit, mais cela ne fonctionne toujours pas :(

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))

Mais là encore ... cela ne fonctionne que si j'appelle init à l'intérieur de download.

8
vajehu

Le problème ici est que init est asynchrone. En l'utilisant comme ceci:

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

La fonction download est en cours d'exécution alors que init n'est toujours pas terminé.

Je n'appellerais pas la méthode init dans le constructeur. Ce que je ferais est quelque chose comme ceci:

1- supprime l'appel init du constructeur.
2- utilise la classe comme ceci:

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

et si vous appelez init dans une fonction async, vous pouvez faire:

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