我有一个片段(下面)会根据几个参数生成请求。它基本上通过区分每个用户的请求来创建类似于JBehaves的负载。在大多数情况下,这很好。请求的生成按预期工作。然而,结果无法正常使用Promise.all()
。这引出了我的问题:
Promise.all()
是否存在问题?
在这个问题中,结果的格式可能看起来有点不稳定,但实质上我只是创建了一个用户数组(这本身只是一个请求结果数组)。
而不是数组中的每个对象都不同,它们都是相同的。在大多数情况下,它似乎是推入阵列的最后一个对象(但我还没有完全证实这一点)。这种行为最初让我相信我的代码片段中存在一个范围问题但是,我一直无法找到它:(
[
[{
hostname: 'google.com',
headers: [Object],
path: '/url1/',
method: 'GET',
date: 1457395032277,
status: 200,
ttfb: 1488
}, {
hostname: 'google.com',
headers: [Object],
path: '/url1/',
method: 'GET',
date: 1457395032277,
status: 200,
ttfb: 1488
}]
]
我希望Promise.all()
会返回一个(promise)解析为具有多个对象的数组 - 每个对象都不同,以反映tasks()
中定义的每个任务的结果。
[
[{
hostname: 'google.com',
headers: [Object],
path: '/url1/',
method: 'GET',
date: 1457395032277,
status: 200,
ttfb: 1488
}, {
hostname: 'bing.com',
headers: [Object],
path: '/url2/',
method: 'GET',
date: 1457395032280,
status: 500,
ttfb: 501
}]
]
如果您注意到注释掉console.dir(stats)
:此行按预期吐出结果(每个任务的结果不同)但是,如果我在reduce的末尾拍了.then()
,则数组是返回为Actual Results
(与Expected Results
)
(为简洁起见,我们假设request()
返回一个承诺)
'use strict';
const request = require('./request');
const Promise = require('bluebird');
module.exports = (tests, options) => {
return Promise.all(users());
////////////
/* generate users */
function users() {
let users = [];
for (let x = options.users; x > 0; x--) {
/* https://github.com/petkaantonov/bluebird/issues/70#issuecomment-32256273 */
let user = Promise.reduce(tasks(), (values, task) => {
return task().then((stats) => {
// console.dir(stats);
values.push(stats);
return values;
});
}, []);
users.push(user);
};
return users;
}
/* generate requests per user */
function tasks() {
let tasks = [];
for (let id of Object.keys(tests)) {
for (let x = options.requests; x > 0; x--) {
let task = () => {
let delay = options.delay * 1000;
return Promise.delay(delay).then(() => request(tests[id]));
};
tasks.push(task);
};
}
return tasks;
}
};
'use strict';
const https = require('follow-redirects').https;
const sprintf = require('util').format;
const Promise = require('bluebird');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
let request = (req) => {
return new Promise((resolve) => {
let start = Date.now();
let ttfb;
let cb = (res) => {
req.status = res.statusCode;
res.on('data', (chunk) => {
if (!ttfb) ttfb = Date.now() - start;
});
res.on('end', () => {
req.ttfb = ttfb;
req.end = Date.now() - start;
resolve(req);
});
res.on('error', (err) => {
req.error = err;
resolve(req);
});
};
/* convert cookies for convenience */
if (req.headers.cookies) {
let cookies = [];
for (let cookie of Object.keys(req.headers.cookies)) {
cookies.push(sprintf('%s=%s', cookie, req.headers.cookies[cookie]));
}
req.headers.cookie = cookies.join('; ');
req.cookies = req.headers.cookies;
delete req.headers.cookies;
}
https.request(req, cb).end();
});
};
module.exports = request;
$ npm --version
2.14.12
$ node --version
v0.12.9
非常感谢任何帮助!
答案 0 :(得分:3)
Promise.all()
是否存在问题?
没有。
而不是数组中的每个对象都不同,它们都是一样的。
事实上。它们都是同一个对象。
你的request
function无论出于什么原因 - 通过其参数解决其返回的承诺。当您将同一个tests[id]
对象传递给批处理的所有请求时,它们都将以此对象结束。
您的console.dir
确实显示了预期的结果,因为request
确实改变了它的参数 - 测试对象在每次调用后包含不同的值,随后会被记录,然后在下一次调用中被覆盖。
您应该更改cb
以创建新对象,而不是改变req
:
function cb(response) {
let result = {
status: response.statusCode
};
response.on('data', (chunk) => {
if (!ttfb) ttfb = Date.now() - start;
});
response.on('end', () => {
result.ttfb = ttfb;
result.end = Date.now() - start;
resolve(result);
});
response.on('error', (err) => {
result.error = err;
resolve(result);
});
}