等待以Typescript

时间:2018-08-27 23:43:57

标签: typescript promise async-await request-promise

我是.Net开发人员,刚接触javascript / node领域,因此在使用request-promise请求从网页获取HTML时遇到了一些麻烦。我已经尝试了以下代码的变体。

import cheerio = require('cheerio');
import request = require('request-promise');

export class Address {
    public html;
    public $: CheerioStatic;

    constructor() {
         this.html = this.makeRequest();
    }

    private async makeRequest() {
        const options = {
            uri: 'https://www.google.com/',
            transform(body) {
                return cheerio.load(body);
            }
        };
        return await request(options);
    }
}

问题是,当我通过调用this.makeRequest()方法设置this.html变量时,我得到了Promise { pending }的返回。我不确定为什么会这样。根据我一直在研究的内容,不是在等待,等待诺言被兑现吗?我也尝试过使用.then语法,但是得到了一个更奇怪的结果: Promise {_bitField: 0, _fulfillmentHandler0: undefined, _rejectionHandler0: undefined, _promise0: undefined, _receiver0: undefined, …}。下面是返回奇怪承诺的makeRequest()的版本。

private makeRequest() {
    const options = {
        uri: 'https://www.google.com/',
        transform(body) {
            return cheerio.load(body);
        }
    };
    return request(options)
        .then(function($: CheerioStatic) {
            return $;
        })
        .catch(function(err) {
            //
        });
}

我想坚持使用async / await语法,但是在解释为什么我的代码不起作用以及我能做些什么来解决它方面的任何帮助将不胜感激!

更新

根据@basarat的建议,我使用await关键字设置了另一个异步方法来设置属性。我的代码如下。我也尝试过在getRequest方法中是否使用async / await关键字。无论哪种方式,我的财产现在都返回为undefined。不知道这是否是朝正确方向迈出的一步。

import cheerio = require('cheerio');
import request = require('request-promise');

export class Address {
    public html;
    public $: CheerioStatic;

    constructor() {
        this.getHtml();

        // this.parseHtml();
    }

    private async makeRequest() {
        const options = {
            uri: 'https://www.google.com/',
            transform(body) {
                return cheerio.load(body);
            }
        };
        return await request(options);
    }

    private async getHtml() {
        this.html = await this.makeRequest();
    }
}

更新2

因此,我不知道该怎么做,所以决定再次尝试使用promise路由,使用request模块而不是request-promise。在我的makeRequest()函数中,我返回了一个包装了我的请求的新诺言,然后在.then()方法中对其调用了getHtml()。要注意的另一件事是,我正在通过mocha单元测试来测试此代码。不确定是否与此有关。我试过使测试异步并在那里使用await,但是没有雪茄。下面是我的课程和测试。

import request = require('request');

export class Address {
    public html;

    constructor() {
        this.html = this.getHtml();
    }

    public getHtml() {
        this.makeRequest().then((body) => {
            console.log(body);
            return body;
        });
    }

    private makeRequest() {
        return new Promise(function(resolve, reject) {
            request('https://www.google.com/', function(error, response, body) {
                if (error) {
                    reject(error);
                }
                resolve(body);
            });
        });
    }
}

最后一个观察。我在getHtml()方法中放入了console.log(body);来查看它是否被调用。当我运行单元测试并将断点放在测试中的任何位置时,即使我已经创建了类的实例,也从未调用过该断点。但是,当我继续执行并完成测试时,它会打印出所有HTML!因此,对我来说,最新的代码似乎还不错,但是可能存在某种时序问题。由于HTML仍会打印出来,因此至少会进行该调用,但不会对我的媒体资源进行调用。下面是我正在执行的测试。

describe('Address', () => {
    // const address = new Address();
    it('is not empty', () => {
        const address = new Address();
        const ad = address.html;
        // console.log(ad);
    });
});

此外,在测试中,我尝试使it语句异步并将await添加到a​​ddress.html(也尝试等待实例化),并且再次没有雪茄。

3 个答案:

答案 0 :(得分:0)

  

当我通过调用this.makeRequest()方法设置this.html变量时,我得到Promise {未决}的返回。我不确定为什么会这样。

因为async函数返回了一个Promise。

修复

从其他异步函数(不是构造函数)中移动调用异步函数并使用await。

答案 1 :(得分:0)

我不清楚您的班级正在尝试建模什么。几句话  虽然。  如果您的班级正在建模某种价值并试图隐藏这种价值  在其私有功能内获得/创造的价值,应使其  消费者意识到这是一个“异步”值。  这意味着尽管您的程序由于this.html是  在异步函数中分配的,实际上在  特定事件(此示例中请求的解决方案)。消费者  从类型的角度来看,这是没有办法的。

一种解决方案是简单地向this.html分配一个承诺,例如

class Adress {
  html: Promise<theRealTypeOfHtml>
  ...
  constructor () {
      this.getHtml();
  }
  // no more async
  private getHtml () {
    this.html = this.makeRequest()
  }
}

使用此方法,任何使用者现在都知道通过创建此方法的实例  类,它返回一个对象,该对象的html字段包含一个promise  解决任何您想要html的问题。  实际上,这意味着此类消费者将强烈  鼓励在async上下文中使用它:

async function main () {
  const anAdress = new Adress();
  const html = await anAdress.html;
}

总而言之,您只是在使用者级别提升了异步上下文 生产者级别的。

答案 2 :(得分:0)

我终于找到了解决方案!我实质上做了一个异步函数,该函数调用了request方法,然后不得不进行一个异步测试,以等待我的异步方法调用。总而言之,似乎我必须要有一种方法来实例化所有东西,而在构造函数中不能这样做。如果有人可以弄清楚为什么会这样,那真是太棒了,因为这似乎与我直觉相反。我的意思是,这不是构造函数的目的吗?也许,如果我在任何地方都找不到它,我会发布另一个问题。无论如何,我的代码在下面。

array_sum($lastSixMonths)

这是我的测试方法。

import request = require('request');

export class Address {
    public html;

    constructor() {
        //
    }

    public async getHtml() {
        return await this.makeRequest()
            .then((body) => {
                this.html = body;
            });
    }

    public makeRequest() {
        return new Promise(function(resolve, reject) {
            request('https://fakena.me/random-real-address/', function(error, response, body) {
                if (error) {
                    reject(error);
                }
                resolve(body);
            });
        });
    }
}