Обещать обратные вызовы, которые используют ограничитель скорости - PullRequest
0 голосов
/ 28 августа 2018

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

const RateLimiter = require('limiter').RateLimiter;
const limiter = new RateLimiter(1, 'second');

request(url,{json:true}function(err,res,body){
    let bunchOfURLs = body['bunchOfURLs'];
    for(let i = 0; i < bunchOfURLs.length;i++){
        limiter.removeTokens(1,function(){
            request(bunchOfURLs[i],{json:true},function(err2,res2,body2){
                let moreURLs = body2['moreURLs'];
                for(let j = 0; j < moreURLs.length;j++){
                    request(moreURLs[j],function(err3,res3,body3){
                        // Once all downloads are done console.log('Done!')
                    });     
                }           
            });     
        }
    }
});

Я думаю, что правильнее было бы вложить все функции в обещания и использовать Promise.all для каждой из них. Проблема в ограничителе скорости, я думаю, что вложенные обещания не будут добавлены в массив promises до вызова Promise.all.

const RateLimiter = require('limiter').RateLimiter;
const limiter = new RateLimiter(1, 'second');

request(url,{json:true}function(err,res,body){
    let bunchOfURLs = body['bunchOfURLs'];
    let promises = [];
    for(let i = 0; i < bunchOfURLs.length;i++){
        promises.push(new Promise((resolve,reject)=>{
            limiter.removeTokens(1,function(){
                request(bunchOfURLs[i],{json:true},function(err2,res2,body2){
                    let moreURLs = body2['moreURLs'];
                    for(let j = 0; j < moreURLs.length;j++){
                        // I dont' think these will be added
                        promises.push(new Promise((resolve,reject)=>{
                            request(moreURLs[j],function(err3,res3,body3){
                                resolve();
                            });                                 
                        }))
                    }           
                });     
            }           
        }))
    }
    Promise.all(promises).then(()=>{console.log('Done!')});
});

1 Ответ

0 голосов
/ 28 августа 2018

Если вы планируете использовать Promises с модулем limiter, то вы можете создать простой метод обертки для удаления токена. Также было бы идеально использовать модуль request-promise или создать еще одну простую оболочку для выполнения запросов.

Это будет выглядеть примерно так:

function removeTokens(tokens) {
    return new Promise((resolve) => {
        limiter.removeTokens(tokens, resolve);
    });
}

request(url, {json: true}).then((body) => {
    let promises = body['bunchOfURLs'].map((url2) => {
        return removeTokens(1).then(() => {
            return request(url2, {json:true}).then((body2) => {
                let promises2 = body2['moreURLs'].map((url3) => {
                    return request(url3);
                });
                return Promise.all(promises2);
            }); 
        });
    });
    return Promise.all(promise);
});

И если вы решите создать простую обертку вместо request-promise:

function requestJSON(url) {
    return Promise((resolve, reject) => {
        request(url, {json: true}, (err, res, body) => {
            if (err) {
                reject(err);
            } else {
                resolve(body);
            }
        });
    });
}

Последующее редактирование. Вы можете обработать «повтор», перехватив ошибку и выполнив запрос еще раз.

requestJSON(url).catch((err) => {
    if (err.code === 'ECONNTIMEOUT' || err.code === 'ECONNRESET') {
        return requestJSON(url)
    } else {
        return Promise.reject(err);
    }
});

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...