0

我有一个小程序,它通过将速率和几个小时相乘来计算总数。

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

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)
4

3 回答 3

0

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

所以像:

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

然后在你的调用方法中解析promise then,你将有一个数组作为回调函数的参数,其中每个元素都是相应promise的返回值。

于 2017-05-24T17:35:27.697 回答
0

我相信会发生这种情况,因为 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*/)
于 2017-05-24T17:36:21.117 回答
0

您的代码存在多个问题:

  1. 首先,一旦您在函数中涉及任何异步操作,该函数的结果将是异步的。您根本无法同步返回它。异步操作稍后完成。该函数本身在异步操作完成之前返回。

  2. 因此,您从任何使用异步操作的函数返回一个 Promise,调用者使用该 Promise 来了解事情何时完成或获得最终结果。

  3. 你的功能getTask()很好。它返回一个承诺。该.then()函数内部是多余的,不需要,因为它task似乎已经是 promise 的解析值。

  4. 您的函数getTasks()正在尝试同步 return taskRateMap,但正如您在测试中看到的那样,还没有一个 Promise 已经解决,所以还没有任何值taskRateMap。在我的代码版本中,我在Promise.all()内部使用来了解所有getTask()操作何时完成,并返回一个已解析值是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
});
于 2017-05-24T20:10:21.843 回答