Я разработчик .Net, новичок в мире javascript/node, и у меня возникли проблемы с запросом на получение 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.html, вызывая метод this.makeRequest(), я возвращаю 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 для установки свойства. Мой код ниже. Я также пробовал с ключевыми словами async/await и без них в методе getRequest. В любом случае моя собственность теперь возвращается как 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
Итак, не зная, что делать, я решил снова попробовать маршрут обещаний с модулем запроса вместо запроса-обещания. В моей функции makeRequest()
я возвращаю новое обещание, которое упаковывает мой запрос, а затем вызывает для него .then()
в методе getHtml()
. Еще одна вещь, которую следует отметить, это то, что я тестирую этот код с помощью модульных тестов мокко. Не уверен, что это как-то связано. Я пытался сделать тест асинхронным и использовать там ожидание, но не сигару. Ниже мой класс и тест.
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);
});
});
}
}
Последнее наблюдение. Я вставил console.log(body);
в метод getHtml(), чтобы увидеть, вызывается ли он. Когда я запускаю модульный тест и ставлю точку останова в любом месте теста, он никогда не вызывается, хотя я создал экземпляр своего класса. Однако, когда я продолжаю выполнение и заканчиваю тест, он распечатывает весь 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
в address.html (также пытался дождаться создания экземпляра), и снова без сигары.