我试图建立一个对象数组并发送给客户端。收到错误:
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:357:11)
at ServerResponse.header (D:\Dropbox (Personal)\coding\coinTracker5\node_modules\expr ess\lib\response.js:725:10)
at ServerResponse.send (D:\Dropbox (Personal)\coding\coinTracker5\node_modules\expres s\lib\response.js:170:12)
at ServerResponse.json (D:\Dropbox (Personal)\coding\coinTracker5\node_modules\expres s\lib\response.js:256:15)
at D:\Dropbox (Personal)\coding\coinTracker5\routes\index.js:58:11
at D:\Dropbox (Personal)\coding\coinTracker5\node_modules\cryptox\lib\index.js:51:9
at D:\Dropbox (Personal)\coding\coinTracker5\node_modules\cryptox\lib\bitfinex.js:93: 13
at D:\Dropbox (Personal)\coding\coinTracker5\node_modules\cryptox\lib\bitfinex.js:72: 13
at Request._callback (D:\Dropbox (Personal)\coding\coinTracker5\node_modules\bitfinex -api-node\rest.js:95:16)
at Request.self.callback (D:\Dropbox (Personal)\coding\coinTracker5\node_modules\requ est\request.js:187:22)

我认为res.json(rates)
只会触发一次,所以我不确定为什么标题会被设置两次?
另外如果有更好的方法来构建这个数组并将其发送给客户端,请赐教!谢谢
var rates = [];
for (var i = 0, len = cryptoxArray.length; i < len; i++) {
cryptoxArray[i].getRate({
pair: "XBT_USD"
}, function(err, rateResponse) {
if (!err)
rates.push(rateResponse);
if (i == len) {
console.log('rates: ' + rates);
res.json(rates);
}
});
&#13;
答案 0 :(得分:1)
您的res.json
位于for
循环内。循环将完成迭代并在工作之前调用res.json
以获取速率。如果您希望获得所有费率,则可能需要等待所有getRate
次呼叫完成才能响应。我会使用承诺。
// if getRate returned a promise
var rates = cryptox.map(item => new Promise((resolve, reject) => {
item.getRate({pair:'XBT_USD'}, (err, rate) => {
if (err) return reject(err);
return resolve(rate);
})
})
Promise.all(rates)
.then(res.json);
我现在意识到只是说使用Promises并没有多大帮助。这是一个非承诺版本。这是在飞行中放在一起,但应该工作。
function mapAsync (fn, list, cb) {
var newList = [];
var i = 0;
function counter (err, value) {
console.log('count', value)
if (err) return cb(err);
newList.push(value);
if (i === list.length -1) return cb(newList);
i++;
callItem();
}
function callItem () {
return fn(list[i], counter)
}
return callItem();
}
function getRateFromItem (item, cb) {
return i.getRate({pair:'XBT_USD'}, cb);
}
mapAsync(getRateFromItem, cryptoxArray, (err, values) => {
// as long as there is no err you should have your array of values
})
答案 1 :(得分:1)
当任何回调被调用时,我已经等于长度,你不能使用这样的循环。我的建议是使用promisses并为此或生活做一个Promose.all。
iiefe
for(i, len, etc){
(function(index){do your stuff here})(i)
}
我个人最喜欢的就是这些。
import Promise from 'bluebird';
Promise.all(
cryptoxArray.map(
item => Promise.promisify(item. getRate)({pair: "XBT_USD"})
.then(rate => rate, error => null)
)
)
.then(rates => rates.filter(rate => rate !== null))
.then(res.json);
答案 2 :(得分:0)
在发送响应之前,只需使用async来等待所有异步回调:
var rates = [];
async.each(cryptoxArray, function(e, callback) {
e.getRate({
pair: "XBT_USD"
}, function(err, rateResponse) {
if (!err){
rates.push(rateResponse);
}
callback();
});
},
function(err){
return res.json(rates);
});
答案 3 :(得分:0)
我最近遇到了一个类似的问题,我正在寻找属于一组属性的所有数据,这些属性属于一个父属性,经过一天的尝试,又找到了以下片段的解决方案:>
Model.find({field: req.params.id})
.then(response1 => {
let myexpected = response1.map(item => new Promise((resolve, reject) => {
Model2.find({field: item._id}, (err, resolveData) => {
if (err) return reject(err);
return resolve(resolveData);
})
}));
Promise.all(myexpected)
.then(expectedData => {
console.log(expectedData);
res.status(200).json({data: expectedData});
})
})
我希望对您有所帮助,或者对寻求类似解决方案的另一个人有所帮助。