【问题标题】:Array of Promises, passing variables used in creationPromises 数组,传递创建中使用的变量
【发布时间】:2018-01-25 23:31:58
【问题描述】:

使用 Express,我正在使用 .map 创建一组 API 调用,我希望将其结果合并到一个响应对象中。由于每次调用都使用不同的查询参数,我想使用查询参数作为响应对象的键。

我使用 axios 创建 GET 请求,它返回一个承诺,然后我使用 axios.all 等待所有承诺解决。

问题是,在 promise 解决后,我不再能够访问用于创建它们的变量。如何将这些变量附加到 Promise 以供以后参考?

这里是 API:

router.get('/api', (req, res) => {
  const number = req.query.number;
  res.json({ content: "Result for " + number });
});

这是我尝试合并结果的地方:

router.get('/array', async (req, res) => {
  res.locals.payload = {};
  const arr = [1, 2, 3, 4, 5];
  const promises = arr.map(number => {
    return axiosInstance.get('/api', { params: { number: number } })
  });
  const results = await axios.all(promises);
  results.map(r => {
    // number should match original, but I no longer have
    // access to the original variable
    number = 1;
    res.locals.payload[number] = r.data;
  });
  res.json(res.locals.payload);
});

/array 上的 GET 结果:

{
    "1": {
        "content": "Result for 5"
    }
}

在创建 Promise 对象以保留密钥时我可以做什么?

【问题讨论】:

标签: javascript express promise


【解决方案1】:

如果结果将是一个索引从 0 开始的数组,而不是一个具有“1”、“2”等属性的对象,我们可以使用Promise.all(或axios.all,如果它提供同样的保证Promise.all 确实,它给你的数组将按照你给它的承诺的顺序排列,无论它们解决的顺序如何)。但我猜你的“数字”确实是更有趣的东西的占位符。 :-)

您可以利用 Promise 是一个管道这一事实来做到这一点,其中各种处理程序会在此过程中转换内容。

在这种情况下,您可以将get 调用的结果转换为带有数字和结果的对象:

const promises = arr.map(number => {
  return axiosInstance.get('/api', { params: { number } })
         .then(result => ({result, number}));
});

现在,results 在您的 all.then 回调中接收到具有 resultnumber 属性的对象数组。如果您愿意,可以使用解构参数在您的 results.map 回调中接收它们:

//           vvvvvvvvvvvvvvvv---------------- destructuring parameters
results.map(({result, number}) => {
  res.locals.payload[number] = result.data;
//                   ^^^^^^----^^^^^^-------- using them
});

现场示例:

// Fake axiosInstance
const axiosInstance = {
    get(url, options) {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve({data: `Data for #${options.params.number}`});
            }, 300 + Math.floor(Math.random() * 500));
        });
    }
};
// Fake axios.all:
const axios = {
    all: Promise.all.bind(Promise)
};

// Fake router.get callback:
async function routerGet() {
    const payload = {}; // stand-in for res.locals.payload
    const arr = [1, 2, 3, 4, 5];
    const promises = arr.map(
      number => axiosInstance.get('/api', { params: { number } })
                             .then(result => ({result, number}))
    );
    const results = await axios.all(promises);
    results.map(({result, number}) => {
      /*res.locals.*/payload[number] = result.data;
    });
    console.log(/*res.locals.*/payload);
}

// Test it
routerGet().catch(e => { console.error(e); });

请注意,我在上面使用了 ES2015+ 属性简写,因为您使用的是箭头函数等。对象初始化器{ number }{ number: number } 完全相同。


附注 2:如果您愿意,可以为 map 回调使用简洁的箭头函数:

const promises = arr.map(
  number => axiosInstance.get('/api', { params: { number } })
                         .then(result => ({result, number}))
);

【讨论】:

    猜你喜欢
    • 2018-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多