I have a snippet (below) that will generate requests based on a couple of params. It essentially creates load similar to JBehaves by distinguishing requests per user. For the most part, this works fine. Generation of requests works as expected. The results however are not working as one would expect using Promise.all()
. Which leads me to my question:
Is there an issue with Promise.all()
?
The format of the results may look a little wonky in this question but, essentially I'm just creating an array of users (which in itself is just an array of request results).
Instead of each object within the array being different, they're all the same. In most case, it appears to be the last object pushed into the array (but I haven't fully confirmed this). This behavior initially lead me to believe there was a scoping issue within my snippet but, I haven't been able to find it :(
[
[{
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
}]
]
I would expect that Promise.all()
would return a (promise) resolving to an array with multiple objects - each one being different as to reflect the results from each task as defined in 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
}]
]
If you notice the commented out console.dir(stats)
: this line spits out the results as expected (different results per task) but, if I slap a .then()
on the end of the reduce, the array is returned as Actual Results
(vs. Expected Results
)
(For brevity, let's assume request()
returns a promise)
'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
Any help would be greatly appreciated!
Is there an issue with
Promise.all()
?
No.
Instead of each object within the array being different, they're all the same.
Indeed. They are all the same object.
Your request
function does - for whatever reason - resolve its returned promise with its argument. As you are passing the very same tests[id]
object to all requests of a batch, they all will end up with this object.
Your console.dir
did show the expected results because request
does mutate its argument - the test object contains different values after every call, which are subsequently logged, before being overwritten in the next call.
You should change that cb
to create a new object, instead of mutating 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);
});
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.