ES6类中的async/await。

13

我想创建一个类,该类将发送一个post请求(登录),保存cookie并将该cookie用于其他操作,如下载文件。

我创建了一个本地服务器,该服务器将接收带有用户名和密码的post http方法以及一个名为/download的路由器,只有在用户登录后才能访问该路由器,否则它将返回你需要登录

问题是: 这是我的类的原型(事先):

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进行两个操作,即下载查询。因此,我考虑创建一个init方法来执行登录等初始操作,并在构造函数中调用它,以使其初始化并将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))
}

只有在download方法中调用init,它才能正常工作。

如果我将console.log(this.cookie)放在download中,则返回一个空的CookieJar,如果我将相同的东西放在init中,则会返回正确的cookie,但是它似乎出现在download执行之后,尽管我在调用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))

但是再怎么样...只有在我调用download函数内部的init函数时才能起作用。


@JaromandaX 我不明白为什么我需要返回任何东西,因为initdownload内部的操作不需要在任何地方共享,并且request-promise-native会将jar放入this.cookie中(我所需要的),但问题是运行顺序。在download中添加await init()的行为就像“我必须等待init完成然后继续”(大致如此),但由于我在构造函数中调用了this.init,所以我认为这是不必要的。 - vajehu
没关系,你尝试帮忙了,我完全理解你的意思。无论如何,还是谢谢你。 - vajehu
现在的问题是download不会等待init - Jaromanda X
在构造函数中,尝试添加 this.initp = this.init(); ... 然后在 download 中将 await this.initp; 添加为第一行。 - Jaromanda X
我不想在每个需要 cookie 的方法中都调用 init,所以我想:我能不能创建一个方法,在构造函数中只调用一次,然后在其他地方随处使用呢?理论上看起来很完美,但实际上并不是这样。我认为 await 可以解决问题,并且由于我正在使用 ImageDownloader 的具体方法调用 download,所以我认为它会在 init 之后调用 download - vajehu
显示剩余7条评论
1个回答

2
这里的问题在于init是异步的。像这样使用它:
const downloader = new ImageDownloader;
downloader.download();

download函数在init尚未完成执行时被调用。

我不会在构造函数中调用init方法。我会做如下操作:

1- 从构造函数中移除init调用。
2- 使用类似以下方式使用该类:

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

如果你在一个async函数中调用init,你可以这样做:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接