2016-11-24 3 views
1

Я делаю два последовательных вызова API, используя node.узел ждет ответа от одного запроса GET перед запуском следующего

Во-первых, я делаю запрос GET, после которого я использую данные из ответа, чтобы сделать второй запрос GET. Я хочу, чтобы первый вызов API закончился, прежде чем запускать второй вызов.

Я попытался использовать оба пакета узлов request/request-promise, чтобы сделать серверную команду GET запросить API Spotify.

Первоначально я использовал request, но только что установил request-promise. Возможно, это не обязательно. См. Мой код ниже. Может ли кто-нибудь заметить любую очевидную ошибку, которую я делаю? Я ожидал, что работать после following this post.

var request = require('request-promise'); 

request(url, function(error, response, body) { 
    var body = JSON.parse(body); 
    for (var i = 0; i < body.length; i++) { 
    test.push(body[i].url) 
    } 

} 
res.send(req.body); 
}).then(function() { 
    for (var i = 0; i < test.length; i++) { 
    request(url2, function(error, response, body) { 
     test2.push(body); 
    }); 
    } 
}) 

ответ

0

Использованием 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); 
    } 
} 
+0

спасибо за очень тщательный ответ. код выглядит несколько раздутым: -S –

+0

Я дал вам ответ с наименьшим количеством изменений в вашем коде, а затем с использованием ES6, который в основном представляет собой 3 строки кода, не уверен, что раздувается по этому поводу: P. Я даже добавил решение, используя обратные вызовы, которые покажут вам, насколько это было бы больно, если бы у нас не было обещаний :) – nem035

+0

Я действительно ценю это. Я не имею в виду, что ваш код раздувается, просто метод кажется более подробным, чем я ожидается. –

Смежные вопросы