在下游的早期承诺中访问variables

本质上在下面的脚本中,我想知道什么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需要重写的问题。

       

网上收集的解决方案 "在下游的早期承诺中访问variables"

Akaphenom,为了在链条上获得可用的结果,你总是可以使用一个或多个外部variables,但使用这种types的模式可能更干净:

 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 ,我已经拿出重复代码并创build了一个辅助函数propagate()

EDIT2

还有一个更有说服力的DEMO版本,每个阶段都有一个setTimeout延迟。

编辑3

这就是模式与助手函数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 }); 

我正在将原始的HTTP请求拉出与请求一起传输的response.node.req对象。 不幸的是 – 这不是我的问题的答案,而是解决我的问题。 不幸的是,我引用了一个由下划线表示的variables,这让我有些紧张。 好的,我正在运行一个简单的脚本 – 但不是一个很好的解决scheme。

 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() })