是否可以继续暂停异步功能? (2)

时间:2017-12-07 12:39:04

标签: javascript promise async-await

我在之前的代码中进行了一些更改,运行了更多测试,并且我再次遇到了同样的问题(Is it possible continue a stopped async function?)。所以这个问题是相关的。

此外,之前的解决方案不起作用。



var stop = false;
var pause = false;
var elParrafo = document.getElementById('miParrafo');

function sendPause() {
  pause = true;
}

function sendContinue() {
  pause = false;
}

function sendStop() {
  stop = true;
}

function longWork(ms, char) {
  return new Promise(function(resolve, reject) {
    elParrafo.innerHTML += char;
    setTimeout(resolve, ms);
  });
}

async function doIt() {
  for (var i = 0; i < 666; i++) {
    if (!stop) {
      if (!pause) {
        await longWork(50," > ");
      }
    } else {
      break;
    }
  }
}

doIt();
&#13;
<form class="" action="index.html" method="post">
  <input type="button" value="Pause" onclick="sendPause()">
  <input type="button" value="Continue" onclick="sendContinue()">
  <input type="button" value="Stop" onclick="sendStop()">
</form>
<p id="miParrafo"></p>
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:4)

当你暂停任务时,你必须实际暂停它并等到用户想要继续,不要继续你的循环直到结束但没有做任何工作。

var stopped;
var paused;
var waitingContinuations;

function sendStart() {
  stopped = false;
  paused = false;
  waitingContinuations = [];
  doIt();
}

function sendPause() {
  paused = true;
}

function sendContinue() {
  paused = false;
  for (const cont of waitingContinuations)
    cont();
  waitingContinuations.length = 0;
}

function sendStop() {
  stopped = true;
}

async function doIt() {
  document.getElementById('output').textContent = "";
  for (var i = 0; i < 666; i++) {
    // in places where you might want to abort, put this:
    if (stopped) return; // or throw new Error("stopped");
    // in places where you might want to pause, put this:
    if (paused) await new Promise(resolve => waitingContinuations.push(resolve));

    await longWork(50, " > ");
  }
}

function longWork(ms, char) {
  return new Promise(resolve => {
    document.getElementById('output').textContent += char;
    setTimeout(resolve, ms);
  });
}
<form>
  <input type="button" value="Start" onclick="sendStart()">
  <input type="button" value="Pause" onclick="sendPause()">
  <input type="button" value="Continue" onclick="sendContinue()">
  <input type="button" value="Stop" onclick="sendStop()">
</form>
<p id="output"></p>

答案 1 :(得分:3)

将flags设置为true时会出现此问题。在取消设置标志时,异步代码会耗尽循环的其余部分。你可以用一些承诺绕过它。

let stop = false;
let isPaused = false;
let resolvePause = () => {};
let pauseProm = Promise.resolve();
const elParrafo = document.getElementById('miParrafo');

function sendPause() {
  if(isPaused) return;

  isPaused = true;
  pauseProm = new Promise(resolve => resolvePause = resolve);
}

function sendContinue() {
  isPaused = false;
  resolvePause();
}

function sendStop() {
  stop = true;
}

function longWork(ms, char) {
  return new Promise(function(resolve, reject) {
    elParrafo.innerHTML += char;
    setTimeout(resolve, ms);
  });
}

async function doIt() {
  for (let i = 0; i < 666; i++) {
    if (stop) break;

    await pauseProm;
    await longWork(50," > ");
  }
}

doIt();
<form class="" action="index.html" method="post">
  <input type="button" value="Pause" onclick="sendPause()">
  <input type="button" value="Continue" onclick="sendContinue()">
  <input type="button" value="Stop" onclick="sendStop()">
</form>
<p id="miParrafo"></p>

答案 2 :(得分:0)

这是一个使用setInterval的简单解决方案:

&#13;
&#13;
var task = (function(){
  var timer;
  var taskImplementation;
  var max;
  var ms;
  var timesRun = 0;
  var isPaused = false;
  const runTask = function(){
    if(!isPaused && timesRun<max){
      taskImplementation();
      timesRun++;
    }else{
      clearInterval(timer);
    }
  };
  const reset = function() {
    timesRun=0;
    isPaused=false;    
  };
  const start = function(){
    if(timer){
      stop();
    }
    reset();
    timer = setInterval(runTask,ms);
  };
  const stop = function(){
    reset();
    clearInterval(timer);
  };
  const pause = function(){
    clearTimeout(timer);
  };
  const cont = function(){
    timer = setInterval(runTask,ms);    
  };
  return function(doWhat){
    taskImplementation = doWhat;
    return function(interval){
      ms = interval;
      return function(howManyTimes){
        max = howManyTimes;        
        return {
          start:start,
          stop:stop,
          pause:pause,
          continue:cont
        }
      }
    }
  }
})();
var doWhat = (function(elParrafo){
  return function(){
    elParrafo.innerHTML += " > ";
  }
})(document.getElementById('miParrafo'));
var interval =200;//how long to wait between task execution
var howManyTimes = 666;//how many times to repeat task
window.setParrafoTask = task(doWhat)(interval)(howManyTimes);
&#13;
    <form class="" action="index.html" method="post">
        <input type="button" value="Start" onclick="setParrafoTask.start()">
        <input type="button" value="Pause" onclick="setParrafoTask.pause()">
        <input type="button" value="Continue" onclick="setParrafoTask.continue()">
        <input type="button" value="Stop" onclick="setParrafoTask.stop()">
      </form>
      <p id="miParrafo"></p>
&#13;
&#13;
&#13;