Javascript - Async/Await 计时器在循环中

Javascript - Async/Await Timer in loop

我正在开发“Timeblocks”类型的应用程序(针对 uni)。核心思想是我们有一个子任务列表,每个子任务都有指定的时间限额。我希望能够遍历任务,使用计时器倒计时分配的时间津贴,然后迭代到下一个任务。例如;

var todos = [
  { id: 1, task: "Finance", time: 1 },
  { id: 2, task: "Distribution", time: 1 },
  { id: 3, task: "Blah", time: 1 }
];

我们将遍历上述内容,在控制台中每次倒计时 1 分钟。

我已经对核心功能进行了编码,迭代本身与 async/await 一起工作。

这里是 stackblitz:

https://stackblitz.com/edit/js-87ykxt

但是,倒计时本身在第一次迭代后无法正常工作,并且表现得很奇怪,似乎每秒倒计时两次,然后从未真正停止并进入负数。每次计时器达到 0 时,间隔应该被清除,然后在下一次迭代发生时重新创建。

感谢任何帮助。

P.S。还知道第一次迭代需要 1 分钟才能开始,我也必须解决这个问题!

好吧,我会避免使用全局变量。最好将 parameters/values 作为参数传递给函数。请使用 'let' 和 'const' 而不是 'var'! 为了帮助您理解,我缩短了您的代码并添加了一些调试行。希望现在它能如您所愿地运行 (:

// Import stylesheets
import "./style.css";

// Write Javascript code!

const start = document.getElementById("start");
start.addEventListener("click", startHandler);

var todos = [
  { id: 1, task: "Finance", time: 0.1 },
  { id: 2, task: "Distribution", time: 0.2 },
  { id: 3, task: "Blah", time: 0.2 }
];

var interval;
var mySeconds;

function tick(task, resolve) {
  var min = Math.floor(mySeconds / 60);
  var sec = mySeconds - min * 60;

  if (sec < 10) {
    sec = "0" + sec;
  }

  var message = min.toString() + ":" + sec;

  console.log(message);

  if (mySeconds === 0) {
    alert("Done for " + task);
    clearInterval(interval);
    return resolve();
  }
  mySeconds--;
}

function resolveTimer(time, task) {
  return new Promise(resolve => {
    mySeconds = time;
    interval = setInterval(tick, 1000, task, resolve);
  });
}

async function startHandler() {
  for (let i = 0; i < todos.length; i++) {
    const time = todos[i].time;
    const task = todos[i].task;

    console.log("Starting for task:", task);
    await resolveTimer(time * 60, task);
    console.log(task, " awaited");
  }
}

这就是你可以做的,我将计时器设置为 5 秒而不是 60 秒以便更好地演示:

const todos = [{
    id: 1,
    task: "Finance",
    time: 1
  }, {
    id: 2,
    task: "Distribution",
    time: 1
  }, {
    id: 3,
    task: "Blah",
    time: 1
  }
];

const taskDuration = 5; // 5 instead of 60

async function startHandler() {
  for (const todo of todos) {
    console.log('Current todo', todo.task);
    await countDown(todo.time * taskDuration);
  }
}


startHandler();

function countDown(time) {
  function tick() {
    const min = Math.floor(time / 60);
    let sec = time - min * 60;

    if (sec < 10) {
      sec = "0" + sec;
    }

    const message = min.toString() + ":" + sec;

    console.log(message);

    time--;
  }
  const interval = setInterval(tick, 1000);
  return promiseSetTimeout(() => clearInterval(interval), time * 1000);
}

// Util function to call a function later, and return a Promise
function promiseSetTimeout(fun, time) {
  return new Promise(resolve => setTimeout(() => [fun, resolve].forEach(x => x.call()), time));
}