javascript-ES6 Promise.all()对promises数组的奇怪解析

我有一个代码片段(如下),它将基于几个参数生成请求.通过区分每个用户的请求,它实质上会创建类似于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)解析为具有多个对象的数组-每个对象都不同,以反映task()中定义的每个任务的结果.

[
    [{
        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结果(与预期结果)

(为简便起见,我们假设request()返回一个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

任何帮助将不胜感激!

解决方法:

Is there an issue with Promise.all()?

没有.

Instead of each object within the array being different, they’re all the same.

确实.它们都是同一个对象.

您的request function确实会出于任何原因使用其参数来解决其返回的诺言.当您将相同的tests [id]对象传递给批处理的所有请求时,它们都将以该对象结束.

您的console.dir确实显示了预期的结果,因为请求确实改变了它的参数-测试对象在每次调用之后包含不同的值,这些值随后被记录,然后在下一个调用中被覆盖.

您应该更改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);
  });
}
上一篇:javascript-蓝鸟承诺取消


下一篇:机器学习之tensorflow(一)安装