wake-up-neo.com

ES6 async/await in Klassen

Ich versuche, eine Klasse zu erstellen, die eine Post-Anfrage (Login) sendet, den Cookie speichert und diesen Cookie für andere Vorgänge wie das Herunterladen einer Datei verwendet.

Ich habe einen lokalen Server erstellt, der eine post-http-Methode mit Benutzer und Kennwort sowie einen Router mit dem Namen /download erhält, auf den nur dann zugegriffen werden kann, wenn der Benutzer angemeldet ist. Andernfalls wird you need to log in zurückgegeben.

Das Problem: Dies ist der Prototyp meiner Klasse (vorher):

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

Wie Sie im obigen Code sehen können, brauche ich das Cookie für zwei Vorgänge, nämlich download und query. Daher überlege ich mir, eine init-Methode zu erstellen, die die anfänglichen Vorgänge wie Login ausführen und rechts im Konstruktor aufrufen wird, damit sie initialisiert wird Setzen Sie das Cookie auf die Variable this.cookie, um es überall zu verwenden, aber es funktioniert nicht. Es scheint, dass init nach jeder anderen Methode aufgerufen wird.

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

Es kommt wieder zu mir, dass ich mich einloggen muss (Serverantwort) ... ABER es funktioniert, wenn ich diese Änderung mache:

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

Es funktioniert nur, wenn ich init in der download-Methode aufrufe.

Wenn ich console.log(this.cookie) in download eingebe, wird eine leere CookieJar zurückgegeben, und wenn ich dasselbe in init eingebe, wird das richtige Cookie zurückgegeben. Es erscheint jedochNACHdie Ausführung des Downloads, obwohl ich es vor dem Aufruf von download im Konstruktor aufgerufen habe. .

Wie löse ich das? Vielen Dank.

@bearbeiten

Ich habe die Änderungen vorgenommen, die @ agm1984 und @Jaromanda X mir gesagt hat, aber es funktioniert immer noch nicht :(

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

Aber andererseits ... es funktioniert nicht, wenn ich nicht init innerhalb von download aufrufe.

8
vajehu

Das Problem hier ist, dass init asynchron ist. Verwenden Sie es wie folgt:

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

Die Funktion download wird ausgeführt, während init noch nicht abgeschlossen ist.

Ich würde die init-Methode nicht im Konstruktor aufrufen. Was ich tun würde, ist ungefähr so:

1- Entfernen Sie den Init-Aufruf aus dem Konstruktor.
2- benutze die Klasse wie folgt:

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

und wenn Sie init in einer async-Funktion aufrufen, können Sie Folgendes tun:

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