请原谅相当具体案例的问题,但我认为总体目标可能对其他人有用。
目标:使用多个JSON API网址请求的数据填充MongoDB。
简短的问题:到目前为止,我使用了Bluebird的request-promise取得了一些成功:
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
我认为我应该做所有请求,将结果保存在一个数组中并使用我的数据库保存功能循环它。
我是否应该为此使用Promises?也许我应该使用像async.js这样的东西并按顺序运行我的请求。
非常感谢任何帮助或想法。
答案 0 :(得分:1)
我认为你的问题不是关于bluebird api而是构建你的承诺链。
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' });
答案 1 :(得分: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();
答案 2 :(得分:1)
但是,如果任何承诺被拒绝,如何在没有程序失败的情况下循环遍历一系列URL?
如果从.catch返回除被拒绝的承诺之外的值,您将返回已解决的承诺
因此,您的每个请求的.then都可以返回一个像
这样的对象{
success: true,
result: whateverTheResultIs
}
你的捕获返回
{
success: false,
error: whateverTheErrorIs
}
你真的不需要成功财产,虽然这很方便
所以代码就是 - 假设process(url)
返回一个Promise
Promise.map(urls, url =>
process(url)
.then(result => ({result, success:true}))
.catch(error => ({error, success:false}))
)
.then(results => {
let succeeded = results.filter(result => result.success).map(result => result.result);
let failed = results.filter(result => !result.success).map(result => result.error);
});
或者,在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;
});
});
答案 3 :(得分:-1)
我只是使用请求并使用try catch内部编写我自己的承诺,只能解析。下面的伪示例
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)
}
})
}