【问题标题】:Force async print order with callbacks使用回调强制异步打印顺序
【发布时间】:2026-02-18 00:00:02
【问题描述】:

我正在为我的学生创建一个学习模块,我试图在其中展示 Promise 与回调的威力。不幸的是,我来自 Python 背景,所以回调地狱不是我必须处理的事情。

手头的任务是我想将我用来演示异步如何产生意外结果的示例转换为使用回调产生预期结果的示例。

function print1() {
    mimicAsync(1);
}

function print2() {
    mimicAsync(2);
}

function print3() {
    mimicAsync(3);
}

print1();
print2();
print3();
<script>
function mimicAsync(num) {
	setTimeout(function() {
  	document.getElementById("output").innerHTML += num;
  }, Math.floor(Math.random() * 1000));
}
</script>
<span id="output"></span>

我知道如何使用 Promises 来做到这一点,但我想首先说明回调是多么令人不快。我是在 Promise 被引入之后才开始接触 JavaScript 的,所以对回调地狱的经验很少。

【问题讨论】:

    标签: javascript asynccallback


    【解决方案1】:

    function print1(cb) {
      mimicAsync(1, cb);
    }
    
    function print2(cb) {
      mimicAsync(2, cb);
    }
    
    function print3(cb) {
      mimicAsync(3, cb);
    }
    
    function print4() {
      mimicSync(4);
    }
    
    function print5(cb) {
      mimicAsync(5, cb);
    }
    
    print1(function(err1, data1) {
      if (!err1) {
        print2(function(err2, data2) {
          if (!err2) {
            print3(function(err3, data3) {
              if (!err3) {
                print4();
                print5(function(err5, data5) {
                  if (!err5) {
                    //do next
                  }
                })
              }
            })
          }
        })
      }
    });
    <script>
      function mimicAsync(num, cb) {
        setTimeout(function() {
          document.getElementById("output").innerHTML += num;
          cb(null, 'success'); //return data in callback
        }, Math.floor(Math.random() * 1000));
      }
    
      function mimicSync(num) {
        document.getElementById("output").innerHTML += num;
      }
    </script>
    <span id="output"></span>

    如果我们删除回调并使用 Promises,下面是代码:

    function print1() {
      return mimicAsync(1);
    }
    
    function print2() {
      return mimicAsync(2);
    }
    
    function print3() {
      return mimicAsync(3);
    }
    
    function print4() {
      mimicSync(4);
    }
    
    function print5() {
      return mimicAsync(5);
    }
    
    print1().then(data1 => {
        return print2();
      }).then(data2 => {
        return print3();
      }).then(data3 => {
        print4();
        print5();
      }).then(data5 => { /*do next*/ })
      .catch(err => console.log(err));
    <script>
      function mimicAsync(num) {
        return new Promise((res, rej) => {
          setTimeout(function() {
            document.getElementById("output").innerHTML += num;
            res('success'); //resolve the promise
            //rej('error) to reject the promise
          }, Math.floor(Math.random() * 1000));
        });
      }
    
      function mimicSync(num) {
        document.getElementById("output").innerHTML += num;
      }
    </script>
    <span id="output"></span>

    此外,您可以查看link,其中代码从回调样式代码转换为承诺到异步/等待。

    【讨论】:

    • 我认为我正在努力解决的部分是我认为我可以避免在mimicAsync中设置回调。是因为 print1() 函数本身不是异步部分吗?
    • mimicAsync 是您需要回调的那个,因为该函数有一个异步操作,只有在操作完成后才会返回结果(在回调函数data 参数中)。并且因为print1print2print3 必须等待mimicAsync 的结果,它们也实际上变成了异步的,因此需要回调。为了更清楚,我正在编辑我的答案。添加一个同步的print4,因此不需要回调。但是print5 是异步的,因此需要回调参数。