基本上在下面的脚本中,我想知道导致失败状态的请求的URL。
我是否需要将其封装在对象中并继续向下游传递?
var Q = require('q')
var _ = require('underscore')
var JSON = require('JSON')
var FS = require("q-io/fs");
var HTTP = require("q-io/http");
FS.read('members.json').then(function(memberJson){
return JSON.parse(memberJson)
}).then(function(memberObjects){
var httpCheckPromises = _.chain(memberObjects)
.first(50)
.filter(function(member){
return member.website.toLowerCase().indexOf('www') >= 0
})
.map(function(member){
return HTTP.read(member.website)
})
.value()
return Q.allSettled(httpCheckPromises)
}).then(function(responses){
return _.chain(responses)
.where({state:'rejected'})
.pluck('reason')
.pluck('response')
.value() ;
}).then(function(badResponses){
return _.chain(badResponses)
.filter(function(response) {
return response
})
.map(function(response){
return {
status: response.status
, headers: response.headers
}
})
.value()
}).then(function(responses){
return FS.write("members_with_bad_urls.json", JSON.stringify(responses,null,4))
}).then(function(){
console.log('DONE!')
}).fail(function(reason){
console.log('FAIL!')
console.log(reason)
})
例如在我的第二个代码块中添加一个返回对象
then(function(memberObjects){
var httpCheckPromises = _.chain(memberObjects)
.first(50)
.filter(function(member){
return member.website.toLowerCase().indexOf('www') >= 0
})
.map(function(member){
return {
url: member.website
,response: HTTP.read(member.website)
}
})
.value()
return Q.allSettled(httpCheckPromises)
})
但我认为我的问题需要重写Q.allSettled。
答案 0 :(得分:2)
Akaphenom,为了在链条上提供结果,你总是可以使用一个或多个外部变量,但使用这种类型的模式可能更干净:
promise_returning_function().then(function(x) {
return { x: x } ;//this object will be passed all the way down the .then chain.
}).then(function(obj) {
//here you can read obj.x
obj.y = ...;//add result of this process to obj
//return obj;
}).then(function(obj) {
//here you can read obj.x and obj.y
obj.z = ...;//add result of this process to obj
//return obj;
}).done(function(obj) {
//here you can read obj.x and obj.y and obj.z
});
为了说明模式,我在每个阶段向obj
添加了一个属性(根据问题中的代码),但您可以添加任意数量的属性 - 无,一个或多个 - 无论后续阶段需要什么。
不幸的是,通过以这种方式传播obj
,.then()
返回新承诺的力量就会丧失。但是,以下模式的变体克服了这一点:
promise_returning_function().then(function(x) {
var promise_x = ...;//do something asynchronous here
return Q.when(promise_x, function(result_x) {
return { x: result_x };//this object will be passed all the way down the .then chain.
});
}).then(function(obj) {
//here you can read obj.x
var promise_y = ...;//do something asynchronous here
return Q.when(promise_y, function(result_y) {
obj.y = result_y;
return obj;
});
}).then(function(obj) {
//here you can read obj.x and obj.y
var promise_z = ...;//do something asynchronous here
return Q.when(promise_z, function(result_z) {
obj.z = result_z;
return obj;
});
}).done(function(obj) {
//here you can read obj.x and obj.y and obj.z
});
也许这种模式可以称为"。然后瀑布"?
代码相当冗长,外部var obj = {};
肯定会更简洁,但希望这种模式具有一定的潜在用途。
这是一个 DEMO ,我已经提取了重复的代码并创建了辅助函数propagate()
。
more convincing version of the DEMO ,每个阶段都有setTimeout延迟。
这是辅助函数propagate()
function propagate(p, obj, prop) {
return Q.when(p, function(result) {
obj[prop] = result;
return obj;
});
}
promise_returning_function().then(function(x) {
var promise_x = ...; //do something asynchronous here
return propagate(promise_x, {}, 'x');
}).then(function(obj) {
//here you can read obj.x
var promise_y = ...; //do something asynchronous here
return propagate(promise_y, obj, 'y');
}).then(function(obj) {
//here you can read obj.x and obj.y
var promise_z = ...; //do something asynchronous here
return propagate(promise_z, obj, 'z');
}).done(function(obj) {
//here you can read obj.x and obj.y and obj.z
});
答案 1 :(得分:0)
我将原始HTTP请求从与请求一起传递的response.node.req对象中拉出来。不幸的是 - 不是我的orignial问题的答案,而是我的问题的解决方案。不幸的是我 - 我引用了一个由下划线证明的变量,这让我有些紧张。对于我运行一次的简单脚本,没关系 - dbut不是一个很好的解决方案。
then(function(badResponses){
return _.chain(badResponses)
.filter(function(response) {
return response
})
.map(function(response){
var req = response.node.req
return {
requestUri: req._headers.host + req.path
, httpStatusDesc: friendlyHttpStatus(response.status)
, httpStatus: response.status
, movedTo: response.headers.location
}
})
.value()
})