使用request
库,有没有办法使用promises来简化这个回调?
var context = {};
request.get({
url: someURL,
}, function(err, response, body) {
context.one = JSON.parse(body);
request.get({
url: anotherURL,
}, function(err, response, body) {
context.two = JSON.parse(body);
// render page
res.render('pages/myPage');
});
});
答案 0 :(得分:4)
这是使用Bluebird promises库的解决方案。这会对两个请求进行序列化并将结果累积到context
对象中,并将错误处理汇总到一个地方:
var Promise = require("bluebird");
var request = Promise.promisifyAll(require("request"), {multiArgs: true});
var context = {};
request.getAsync(someURL).spread(function(response, body) {
context.one = JSON.parse(body);
return request.getAsync(anotherURL);
}).spread(response, body)
context.two = JSON.parse(body);
// render page
res.render('pages/myPage');
}).catch(function(err) {
// error here
});
并且,如果您有多个网址,则可以使用蓝鸟等其他一些功能(如Promise.map()
)来迭代一系列网址:
var Promise = require("bluebird");
var request = Promise.promisifyAll(require("request"), {multiArgs: true});
var urlList = ["url1", "url2", "url3"];
Promise.map(urlList, function(url) {
return request.getAsync(url).spread(function(response,body) {
return [JSON.parse(body),url];
});
}).then(function(results) {
// results is an array of all the parsed bodies in order
}).catch(function(err) {
// handle error here
});
或者,您可以创建一个辅助函数来为您执行此操作:
// pass an array of URLs
function getBodies(array) {
return Promise.map(urlList, function(url) {
return request.getAsync(url).spread(function(response.body) {
return JSON.parse(body);
});
});
});
// sample usage of helper function
getBodies(["url1", "url2", "url3"]).then(function(results) {
// process results array here
}).catch(function(err) {
// process error here
});
答案 1 :(得分:2)
以下是我将如何实现链式Promises。
var request = require("request");
var someURL = 'http://ip.jsontest.com/';
var anotherURL = 'http://ip.jsontest.com/';
function combinePromises(context){
return Promise.all(
[someURL, anotherURL].map((url, i)=> {
return new Promise(function(resolve, reject){
try{
request.get({
url: url,
}, function(err, response, body) {
if(err){
reject(err);
}else{
context[i+1] = JSON.parse(body);
resolve(1); //you can send back anything you want here
}
});
}catch(error){
reject(error);
}
});
})
);
}
var context = {"1": "", "2": ""};
combinePromises(context)
.then(function(response){
console.log(context);
//render page
res.render('pages/myPage');
}, function(error){
//do something with error here
});

答案 2 :(得分:1)
使用原生Promises
执行此操作。理解胆量很好。
@Bergi在评论中指出这里称为“Promise Constructor Antipattern”。不要这样做。看看下面更好的方法。
var contextA = new Promise(function(resolve, reject) {
request('http://someurl.com', function(err, response, body) {
if(err) reject(err);
else {
resolve(body.toJSON());
}
});
});
var contextB = new Promise(function(resolve, reject) {
request('http://contextB.com', function(err, response, contextB) {
if(err) reject(err);
else {
contextA.then(function(contextA) {
res.render('page', contextA, contextB);
});
}
});
});
这里有一个漂亮的技巧,我认为通过使用原始承诺,你会明白这一点,contextA
解析一次然后我们可以访问它的解析结果。这是,我们从不向someurl.com
提出上述请求,但仍然可以访问contextA
的JSON。
所以我可以想象创建一个contextC
并重用JSON而不必另外发出请求。 Promises
始终只解析一次。您必须将匿名执行程序函数取出并将其放在new Promise
中以刷新该数据。
奖金说明:
这会并行执行contextA
和contextB
,但会在A
和B
时同时进行需要两种情境的最终计算。 promisifying
已解决。
这是我对此的新尝试。
上述解决方案的主要问题是承诺可重用并且它们不是链接,这是Promises的一个关键特性。
但是,我仍然建议request
您自己的promisifying
库,并且不要在项目中添加其他依赖项。 rejection
自己的另一个好处是你可以编写自己的API
逻辑。如果您正在使用在正文中发送error
条消息的特定//Function that returns a new Promise. Beats out constructor anti-pattern.
const asyncReq = function(options) {
return new Promise(function (resolve, reject) {
request(options, function(err, response, body) {
//Rejected promises can be dealt with in a `catch` block.
if(err) {
return reject(err);
}
//custom error handling logic for your application.
else if (hasError(body)) {
return reject(toError(body));
}
// typically I just `resolve` `res` since it contains `body`.
return resolve(res);
}
});
};
asyncReq(urlA)
.then(function(resA) {
//Promise.all is the preferred method for managing nested context.
return Promise.all([resA, asyncReq(urlB)]);
})
.then(function(resAB) {
return render('page', resAB[0], resAB[1]);
})
.catch(function(e) {
console.err(e);
});
,这一点非常重要。我们来看看:
while (cur->next != NULL)
答案 3 :(得分:1)
您可以使用request-promise库来执行此操作。在您的情况下,您可能会遇到类似这样的问题,您可以在其中链接请求。
request
.get({ url: someURL })
.then(body => {
context.one = JSON.parse(body);
// Resolves the promise
return request.get({ url: anotherURL });
})
.then(body => {
context.two = JSON.parse(body);
res.render('pages/myPage');
})
.catch(e => {
//Catch errors
console.log('Error:', e);
});
答案 4 :(得分:0)
到目前为止最简单的方法是使用request-promise库。您还可以使用bluebird之类的promise库并使用其promisify
函数将request
回调API转换为promise API,但您可能需要将自己的promisify函数编写为{ {1}}不使用标准回调语义。最后,您可以使用本机承诺或蓝鸟来制作自己的承诺包装器。
如果您刚刚开始,请使用请求承诺。如果您正在重构现有代码,我会使用bluebird的request
函数为request
编写一个简单的包装器。