foreach 结束前返回映射的函数

Function returning map before foreach ended

我有这个小程序,它通过将费率乘以一些小时来计算总数。

我遇到的问题是函数 getTasks() 总是 return 一个空映射。 当我记录在地图中输入的字段时,它们不是空的,但它们是在函数 returns 地图之后输入的。 所以我有点困惑为什么会这样。

function getTask(taskId) {
  return rp({
    uri: `${url}/tasks/${taskId}`,
    auth: {
      user: 'user',
      password,
      sendImmediately: false
    },
    json: true
  }).then((task) => {
    return task;
  });
}

function getTasks(entries) {
  const taskIds = [];

  entries.forEach((entry) => {
    const taskId = entry.day_entry.task_id;
    if (!taskIds.includes(taskId)) {
      taskIds.push(taskId);
    }
  });

  const taskRateMap = new Map();

  taskIds.forEach((taskId) => {
    return Promise.resolve(getTask(taskId)).then((res) => {
      if (res.task.id === taskId) {
        taskRateMap.set(taskId, res.task.default_hourly_rate);
        console.log(taskRateMap);
      }
    });
  });
  return taskRateMap;
}

function calculateTasksTotals(id) {
  return co(function* calculateTotalsGen() {
    let total = 0;

    const entries = yield getEntriesForProject(id);

    const tasks = getTasks(entries);

    entries.forEach((entry) => {
      const rate = tasks.get(entry.day_entry.task_id);
      total += rate * entry.day_entry.hours;
    });
    return total;
  });
}

calculateTasksTotals(id)

你的承诺有问题。尝试使用 Promise.all() 提供所有承诺作为输入,并且仅当所有承诺都已解决时才 return 您的地图。 否则直接 return 你的 Promise.all() 并在调用方法中创建地图。

所以像这样:

const tasksPromises = [];
  taskIds.forEach((taskId) => {
    tasksPromises.push(getTask(taskId)); 
  });
return Promise.all(tasksPromises);

然后在您的调用方法中通过 then 解析承诺,您将拥有一个数组作为回调函数的参数,其中每个元素都是相应承诺的 returned 值。

我相信发生这种情况是因为 taskRateMap 在返回之前没有被填充。您可能想查看 Promise.all() 并考虑换行

promises = taskIds.map((taskId) => {
return Promise.resolve(getTask(taskId)).then((res) => {
  if (res.task.id === taskId) {
    return [taskId, res.task.default_hourly_rate];
    console.log(taskRateMap);
  }
});

return Promise.all(promises).then(v => /* taskRateMap*/)

您的代码存在多个问题:

  1. 首先,只要函数中涉及任何异步操作,该函数的结果就会是异步的。您根本无法 return 它同步。异步操作稍后完成。在异步操作完成之前函数本身 returns。

  2. 因此,您 return 来自任何使用异步操作的函数的承诺,并且调用者使用该承诺来知道事情何时完成或获得最终结果。

  3. 你的函数 getTask() 没问题。它 return 是一个承诺。该函数中的 .then() 是多余的,不需要,因为 task 似乎已经是承诺的解析值。

  4. 您的函数 getTasks() 正在尝试同步 return taskRateMap,但是正如您在测试中看到的那样,none 的承诺有尚未解决,因此 taskRateMap 中还没有值。在我的代码版本中,我在内部使用 Promise.all() 来了解所有 getTask() 操作何时完成,并且我 return 已解决值的承诺是 taskRateMap 对象。

  5. getTasks() 的调用者然后可以使用该承诺和 .then() 处理程序来访问 taskRateMap 对象。

这是实现 getTasks() 的一种方法:

function getTasks(entries) {
    // get all unique task_id values from the entries array
    const taskIds = Array.from(new Set(entries.map(entry => entry.day_entry.task_id)));
    const taskRateMap = new Map();

    // use Promise.all() to know when the whole array of promises is done
    // use tasksIds.map() to build an array of promises
    return Promise.all(taskIds.map(taskId => {
        // make this promise be the return value inside the .map() callback
        // so we will end up with an array of promises that will be passed to
        // Promise.all()
        return getTask(taskId).then(res => {
            if (res.task.id === taskId) {
                taskRateMap.set(taskId, res.task.default_hourly_rate);
            }
        })
    })).then(() => {
        // make final resolved value be the taskRateMap
        return taskRateMap;
    });
}

getTasks(entries).then(taskRateMap => {
    // use taskRateMap here
});