来自类方法的异步回调

时间:2018-07-31 18:54:56

标签: javascript node.js asynchronous callback

我正在用JavaScript编写一个类,该类将发送对指定URL的HTTP请求,然后返回响应的正文。我是Node.js和JavaScript的新手,因此,我很难理解Node.js的回调和异步特性。

我写了获取URL的实际方法,并且工作正常。结果可以通过Mocha测试。

class HttpObject {
  constructor () {
    this.url = null
    this.userAgent = null
    this.body = null
  }

  fetchUrl (url, userAgent, callback) {
    this.url = url
    this.userAgent = userAgent

    const request = require('request')
    request(this.url, { timeout: 10000 }, function (error, response, body) {
      if (!error && response.statusCode === 200) {

        //the next line doesn't work, the 'body' field in Mocha test is null
        this.body = response.body
        return callback(response, false)
      } else {
        return callback(null, error)
      }
    })
  }
}

但是当我测试HttpObject的body字段时,它仍被分配为null。不过,应该为它分配结果的主体。

it('should send and http request to https://www.google.com', function (done) {
  httpObj.fetchUrl('https://www.google.com', 'Mozilla/5.0', (res, err) => {
    assert.strictEqual(httpObj.getUrl(), 'https://www.google.com')
    assert.strictEqual(httpObj.getPort(), 80)
    assert.strictEqual(httpObj.getUserAgent(), 'Mozilla/5.0')

    // previous tests pass, but the following doesn't
    assert.notStrictEqual(httpObj.getBody(), null)

    done()
  })
})

2 个答案:

答案 0 :(得分:1)

问题是,从创建该函数的类外部调用函数时,上下文this丢失。 (主要是回调)

在您的情况下,由于function (error, response, body)是从其他地方调用的,因此它不知道this的值。

要解决此问题,您可以使用fat arrow这样的函数:

request(this.url, { timeout: 10000 }, (error, response, body) => {
    // you can now set this.body here safely
})

或者您可以在回调中使用.bind(this)

request(this.url, { timeout: 10000 }, function (error, response, body) {
    // you can now set this.body here safely
}.bind(this))

答案 1 :(得分:0)

您的HttpObject中的this.body语句与其余this值的作用域不同,因为它的回调为request。尝试在请求的回调上方添加var that = this

class HttpObject {
  constructor () {
    this.url = null
    this.userAgent = null
    this.body = null
  }

  fetchUrl (url, userAgent, callback) {
    // add var that
    var that = this;
    this.url = url
    this.userAgent = userAgent

    const request = require('request')
    request(this.url, { timeout: 10000 }, function (error, response, body) {
      if (!error && response.statusCode === 200) {

        // Change the value to that.
        that.body = response.body

        return callback(response, false)
      } else {
        return callback(null, error)
      }
    })
  }
}