Использованием request-promise
для вашего вопроса является хорошей идеей, потому что обещания лучше междуродным обрабатывать код асинхронного, чем обратные вызовы, особенно при работе с несколькими запросами и обработкой ошибок.
Приведенное ниже описание неправильного использования request-promise
. Обратный стиль, который у вас есть, - это способ, которым работает request
, но не обещает.
Успешный обратный вызов в обещаниях передается в крючок then
, а не в первоначальную конструкцию обещаний.
Кроме того, ошибка не передается на успешный (первый) обратный вызов, а попадает в обратный вызов отклонения (второй) (или в catch catch).
Для второго запроса вы на самом деле пытаетесь сделать несколько запросов, по одному для каждого URL-адреса в предоставленном массиве. Чтобы убедиться, что все эти запросы завершены до начала работы, вы должны использовать Promise.all
.
Вот как вы структурируете свои обещания, используя request-promise
.
request({ uri: url, json: true }) // this is how the docs for request-promise say you can request a json
.then(function (json) { // accumulate array of urls and pass them along the promise chain
var urls = [];
for (var i = 0; i < json.length; i++) {
urls.push(json[i].url)
}
return urls;
})
.then(function (urls) {
var promises = [];
for (var i = 0; i < urls.length; i++) {
promises.push(request(urls[i])); // create a promise for each url and fire off the request
}
return Promise.all(promises); // continue down the chain once all promises (request) are resolved
})
.then(function (arrayOfResultsFromEachPreviousRequest) {
// ...
});
Использование ES6 arrow functions и Array.prototype.map, вы можете уменьшить код еще дальше:
request({ url: url, json: true })
.then(json => json.map(item => item.url))
.then(urls => Promise.all(urls.map(url => request(url))))
.then(arrayOfResultsFromEachPreviousRequest => {
// ...
});
Если вы хотите использовать обратный вызов в стиле request
, все было бы гораздо более болезненным, особенно вторая часть, которая ждет нескольких запросов.
Для сравнения, вот подход с использованием обратного вызова (hell) без обработки ошибок:
request.get({ url:url, json:true }, function(err, res, json) {
var urls = [];
for (var i = 0; i < json.length; i++) {
urls.push(json[i].url)
}
makeRemainingRequests(urls, function(arrayOfResultsFromEachPreviousRequest) {
// ...
});
});
function makeRemainingRequests(urls, cb) {
var results = new Array(urls.length).fill(false); // array holding the results of all requests
for (var i = 0; i < urls.length; i++) {
// wrap each request in an IIFE so we have a correct value of i
(function(idx) {
request(urls[idx], function(err, res, body) {
results[idx] = body;
// if all results obtained, call the callback
if (results.every(function (res) { return !!res; })) {
cb(results);
}
});
})(i);
}
}
спасибо за очень тщательный ответ. код выглядит несколько раздутым: -S –
Я дал вам ответ с наименьшим количеством изменений в вашем коде, а затем с использованием ES6, который в основном представляет собой 3 строки кода, не уверен, что раздувается по этому поводу: P. Я даже добавил решение, используя обратные вызовы, которые покажут вам, насколько это было бы больно, если бы у нас не было обещаний :) – nem035
Я действительно ценю это. Я не имею в виду, что ваш код раздувается, просто метод кажется более подробным, чем я ожидается. –