2017-01-21 7 views
0

Пожалуйста, простите, пожалуйста, конкретный вопрос, хотя я думаю, что общая цель цели может быть полезной для других людей.В узле, как я могу запросить JSON из нескольких URL-адресов, используя обещания?

Цель: заполнить MongoDB данными, запрошенными с нескольких URL-адресов API JSON.

Короткий вопрос: До сих пор я имел некоторый успех с request-promise, который использует Bluebird:

var rp = require('request-promise'); 
var options = { 
    uri: 'http://www.bbc.co.uk/programmes/b006qsq5.json', 
    headers: { 
     'User-Agent': 'Request-Promise' 
    }, 
    json: true 
}; 

rp(options) 
    .then(function (body) { 
     // Mongoose allows us query db for existing PID and upsert 
     var query = {pid: body.programme.pid}, 
      update = { 
       name: body.programme.title, 
       pid: body.programme.pid, 
       desc: body.programme.short_synopsis 
      }, 
      options = { upsert: true, new: true }; 

     // Find the document 
     Programme.findOneAndUpdate(query, update, options, function(err, result) { 
      if (err) return res.send(500, { error: err }); 
      return res.send("succesfully saved"); 
     }); 
    }) 
    .catch(function (err) { 
     return res.send(err); 
    }) 

Но как я перебираем массив URL-адреса, без программы неисправной, если какие-либо из обещаний отклоняются? Что-то вроде этого, например, с использованием Bluebird, терпит неудачу, если какая-либо из ошибок URL.

const urls = ['http://google.be', 'http://google.uk'] 

Promise.map(urls, rp) 
    .map((htmlOnePage, index) => { 
    return htmlOnePage; 
    }) 
    .then(console.log) 
    .catch((e) => console.log('We encountered an error' + e)); 

Как я хочу писать в БД с успешными запросами, и игнорировать те, которые не могут быть отвечать прямо тогда, мне нужно что-то, что пропускает отвергнут обещания, которые .all не делают.

Длинный вопрос: Я читаю о обещаниях весь день, и у меня болит голова! Но я нашел хорошие ресурсы, например https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html, в котором упоминается использование фабрики Promise. Будет ли это работать на мое дело? Сначала я думал, что должен сделать каждый запрос, обработать результат и добавить его в БД, а затем перейти к следующему запросу; но, увидев .all, я думал, что должен делать все запросы, сохранять результаты в массиве и перебирать их с помощью моей функции сохранения БД.

Должен ли я использовать Обещания для этого? Возможно, мне нужно просто использовать что-то вроде async.js и запускать мои запросы в серии.

Большое спасибо за любую помощь или идеи.

+1

Если запросы не зависят друг от друга никаких причин, вам нужно все(), чтобы сделать БД обновлений – charlietfl

+0

я думаю, что вы можете использовать async.eachSeries с обещанием. цикл не будет останавливаться даже при возникновении ошибки http://caolan.github.io/async/docs.html#eachOfSeries –

+0

@AsifSaeed mix Обещания с async.js не рекомендуется –

ответ

1

Но как I цикл по массиву URL-адресов, без программы неисправного, если какой-либо из обещаний отвергаются?

если вы возвращаете значение из .catch кроме прерванного обещание, вы вернётесь разрешенную обещание

Итак, ваш.то для каждого отдельного запроса может возвращать объект как

{ 
    success: true, 
    result: whateverTheResultIs 
} 

и ваш улов возвращает

{ 
    success: false, 
    error: whateverTheErrorIs 
} 

Неужели вы не НУЖНЫ свойства успеха, это удобство, хотя

Так что код будет be - при условии, что process(url) возвращает a Promise

Или, в ES5

Promise.map(urls, function (url) { 
    return process(url).then(function (result) { 
     return { result: result, success: true }; 
    }).catch(function (error) { 
     return { error: error, success: false }; 
    }); 
}).then(function (results) { 
    var succeeded = results.filter(function (result) { 
     return result.success; 
    }).map(function (result) { 
     return result.result; 
    }); 
    var failed = results.filter(function (result) { 
     return !result.success; 
    }).map(function (result) { 
     return result.error; 
    }); 
}); 
+0

Большое спасибо за это очень подробное объяснение! Код хорошо читается и имеет смысл для меня. –

-1

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

var request = require('request') 

var urls = ['http://sample1.com/json', 'http://sample2.com/json'] 

var processUrl = (url) => { 
    return new Promise((resolve,reject)=> { 
    var result; 
    try { 
     var myRequest = { 
      uri: url, 
      method: 'GET', 
      header: {...} 
     }; 
     request(option, (res,body,err)=> { 
      if(err) { 
       result = err; 
       return; 
      } 
      result = body; 
     }) 
    } 
    catch(e) { 
     result = e; 
    } 
    finally { 
     resolve(result) 
    } 
    }) 
} 
1

Я думаю, что ваш вопрос меньше о Bluebird апите чем структурирование своего обещание цепи.

const reducePropsToRequests = (props) => Promise.resolve(Object 
    .keys(props) 
    .reduce((acc, key) => { 
    acc[key] = request(sources[key]); 
    return acc; 
    }, {})); 

const hashToCollection = (hash) => Promise.resolve(Object 
    .keys(hash) 
    .reduce((acc, k) => { 
    return [...acc, {source: k, data: hash[k]}]; 
    }, [])); 

const fetchFromSources = (sources) => Promise.props(sources); 

const findSeveralAndUpdate = (results) => Promise 
    .each(results.map(obj => { 
    // you have access to original {a: 'site.com'} 
    // here, so use that 'a' prop to your advantage by abstracting out 
    // your db config somewhere outside your service 
    return Programme.findOneAndUpdate(someConfig[obj.source], obj.data); 
    })) 

const requestFromSeveralAndUpdate = (sources) => reducePropsToRequests(sources) 
    .then(fetchFromSources) 
    .then(hashToCollection) 
    .then(findSeveralAndUpdate) 
    .catch(/* some err handler */); 

requestFromSeveralAndUpdate({ a: 'site.com', b: 'site.net' }); 
+0

Эй, спасибо за этот ответ, лучшая структура - это именно то, что Я ищу. У меня просто возникают проблемы с этим. У меня есть ошибка в 'request (sources [key])', это должно быть 'props [key]'? Кроме того, он, похоже, не обрабатывает ошибочный запрос (например, 404), и я не могу понять, где бы я справился. thnx –

1

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

var heroes = [ 
 
    'Superman', 
 
    'Batman', 
 
    'Spiderman', 
 
    'Capitan America', 
 
    'Ironman', 
 
]; 
 

 
function getHero(hero) { 
 
    return new Promise((resolve, reject) => { 
 
    setTimeout(() => { 
 
     return Math.round(Math.random()) ? resolve(hero + ' lives') : reject(hero + ' dead'); 
 
    }, Math.random() * 3000)  
 
    }) 
 
} 
 

 
function checkHeroes() { 
 
    var checked = heroes.length; 
 
    heroes.forEach((hero) => { 
 
    getHero(hero) 
 
    .then((res) => { 
 
     checked --; 
 
     console.log(res); 
 
     if (!checked) done(); 
 
    }) 
 
    .catch((err) => { 
 
     checked --; 
 
     console.log(err); 
 
     if (!checked) done();  
 
    });   
 
    }) 
 
} 
 

 
function done() { 
 
    console.log('All heroes checked'); 
 
} 
 

 
checkHeroes();

+0

Одним из пунктов использования обещаний является то, что вы можете использовать такие инструменты, как 'Promise.all()', с несколькими обещаниями, а не самостоятельно создавать счетчики для восстановления уже существующих функциональных возможностей. Можно использовать такие счетчики, когда у вас нет обещаний, но на самом деле не следует делать, когда у вас есть обещания. Кроме того, поскольку это обещания Bluebird, есть такие инструменты, как 'Promise.map()', которые будут перебирать коллекцию для вас и возвращать единственное обещание, которое отслеживает все результаты. – jfriend00

+0

Я просто придерживаюсь стандартной реализации обещаний. –

+0

'Promise.all()' - стандартная реализация обещаний. Но вопрос специально отмечен Bluebird и использует Bluebird, поэтому лучший ответ будет использовать то, что упрощает его. – jfriend00

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

  • Нет связанных вопросов^_^