【问题标题】:Make Canvas Animation Asynchronous使画布动画异步
【发布时间】:2018-11-19 10:27:12
【问题描述】:

以下代码是更大项目的一部分:

<body>
  <canvas id="check" width="35px" height="40px" style="background-color: blue;"></canvas>
</body>
<script>
  const check = document.getElementById('check');
  const checkCtx = check.getContext('2d');
  check.onclick = function() {
    drawCheck(checkCtx, 5, 30);
    setTimeout(function() {
      fadeOut(check);
    }, 1000);
    setTimeout(function() {
      check.style.opacity = "1";
      checkCtx.clearRect(0, 0, check.width, check.height);
    }, 2000);
    check.style.backgroundColor = "blue";
  }

  function drawCheck(ctx, x, y) {
    var x1 = x;
    var y1 = y;
    var x2 = x1;
    var y2 = y1;
    var x3 = x1 + 14;
    var y3 = y1 + 7;
    ctx.beginPath();
    ctx.strokeStyle = "green";
    ctx.lineCap = "round";
    ctx.lineWidth = 5;
    ctx.moveTo(x1, y1);

    function draw() {
      x2++;
      y2 += .5;
      ctx.lineTo(x2, y2);
      ctx.stroke();
      if (x2 < x1 + 14) {
        requestAnimationFrame(draw);
      } else {
        function drawNext() {
          x3 += .5;
          y3 -= 1.5;
          ctx.lineTo(x3, y3);
          ctx.stroke();
          if (x3 < x1 + 24) {
            requestAnimationFrame(drawNext);
          } else {
            return;
          }
        }
        drawNext();
        return;
      }
    }
    draw();
  }

  function fadeOut(obj) {
    var opc = 1;
    var finish = false;
    obj.style.opacity = 1;

    function fade() {
      opc -= 0.125;
      obj.style.opacity = opc + "";
      console.log(opc);
      if (opc > 0) {
        requestAnimationFrame(fade);
      }
    }
    console.log("Wait for it...");
    fade();
    console.log("Finished!");
  }
</script>

如果您查看控制台,您可以看到 fadeOut 函数在 fade 函数结束之前结束。因此,我必须使用多个setTimeout 函数。我的其他功能也有同样的问题。我不想依赖这些,那我怎样才能让代码等到被调用的函数返回呢?

【问题讨论】:

    标签: javascript html animation canvas css-animations


    【解决方案1】:

    回调(es5),承诺(es6),异步/等待(es7)

    您希望异步运行代码。这意味着在运行下一个之前等待部分代码完成工作。默认情况下,Javascript 会尽快做所有事情,无论如何。

    不正确:

    function run(){ 
      console.log('1: start run')
      setTimeout(()=>{
        console.log('2: timeout')
      },1000)
    }
    
    function run2(){
      console.log('3: start run2')
      setTimeout(()=>{
        console.log('4: timeout')
      },1000) // change time here and check order console.log's
    }
    
    function run3(){
      console.log('4: start run3')
      setTimeout(()=>{
        console.log('5: timeout')
      },1000)
    }
    run()
    run2()
    run3()

    3 个函数同时启动,它们给出结果而不查看其他 2 个函数中发生的情况。尝试更改超时以更改 conole.log 中的顺序。但在现实生活中,您无法像这里那样控制时间执行。

    回调:

    使用回调,您可以将一个函数嵌套在另一个函数中,并将其作为参数传递。想法是在第二个函数开始之前等待第一个函数执行......在第三个函数之前等待第二个函数......等等。

    function runWithCallback(callback){ // run1
      console.log('1: start runWithCallback()')
      setTimeout(()=>{
        console.log('2: timeout')
        callback(runAfterCallback)
      },1000)
    }
    
    function runCallback(callback){ // run2
      console.log("3: start runCallback()")
      setTimeout(()=>{
        console.log('4: timeout')
        callback()
      },1000)
    }
    
    function runAfterCallback(){ // run3
      console.log("5: start runAfterCallback()")
      setTimeout(()=>{
        console.log('6: timeout')
        // next call back here if needed
      },1000)
    }
    
    runWithCallback(runCallback)

    现在无论每个函数的执行时间有多长,下一个函数都会在第一个函数完成后开始。这样你就不需要猜测执行时间来延迟你的代码了。

    承诺

    在 es6 中,您可以使用 promises 来实现,这在回调函数上是一种语法糖。在撰写本文时,promise 的浏览器覆盖率为 90% https://caniuse.com/#feat=promises

    function run1(){
      console.log('1: run1')
      return new Promise(function(resolve){
        console.log('2: promise')
        setTimeout(resolve,100)
      })
    }
    
    function callback(){
      console.log('3: run2 callback')
      return new Promise(function(resolve){
        console.log('4: promise')
        setTimeout(resolve, 1000)
      })
    }
    
    function callback2(){
      console.log('5: run3 callback')
      return new Promise(function(resolve){
        console.log('6: promise')
        setTimeout(resolve, 100)
      })
    }
    
    run1()
      .then(callback()) // try to change order here, uncoment last lines...
      .then(callback2())
      // .then(callback2())
      // .then(callback())

    【讨论】:

      猜你喜欢
      • 2018-05-06
      • 2020-07-03
      • 1970-01-01
      • 1970-01-01
      • 2014-06-29
      • 2016-08-09
      • 1970-01-01
      • 1970-01-01
      • 2018-04-22
      相关资源
      最近更新 更多