在JS中链接异步函数调用?

use*_*761 2 javascript jquery asynchronous

所以我对JavaScript很新,并且知道异步函数调用.我做了很多研究,发现如果你想连续运行异步调用,你可以使用回调函数和promises.现在我已经了解了如果只运行一些异步函数,这两个实现是如何有用的.我正试图解决一个完全不同的动物; 至少据我所知.我目前正在构建一个网站,需要看起来好像在向自己写文字.只是为了让每个人都知道我的JS代码,这里是写入网页的功能(我是相当新的,所以如果你认为你有一个更好的解决方案,一个小描述的例子将不胜感激):

function write(pageText, elementId, delay) {
  var element = document.getElementById(elementId);
  var charCount = 0;

  setInterval(function() {
    if (charCount > pageText.length) {
      return;
    } else {
      element.innerHTML = pageText.substr(0, charCount++);
    }
  }, delay);
}

write("This is an example", 'someRandomDiv', 100);
Run Code Online (Sandbox Code Playgroud)
<div id="someRandomDiv">

</div>
Run Code Online (Sandbox Code Playgroud)

有了这个,我试图将一行文本一行接一行地写入网页.基本上我用来编写Java和C#中的代码:

function writePassage()
{ 
    var passage=["message one", "message two", "... message n"];
    for(var i = 0; i<passage.length; i++)
    {
        write(passage[i], 'someRandomDiv', 100);
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,因为这不起作用,因为wirtePassage()中的for循环将在一个或两个异步函数调用结束之前完成执行.我问这个错误是否有一个理智的解决方案,我有n个异步调用,我需要在下一个触发之前执行一个.值得一提的是,我不想在上面运行这个循环并添加另一个变量,它只是跟踪我应该延迟每次写入的段落.我更希望是否有一种编程方式在下一个函数被调用之前强制执行该函数.感谢您阅读这个怪物问题!

Bo *_*son 6

为了实现这一目标,您需要做一些事情.

首先,您的write函数需要一个异步接口.正如您所提到的,它可以采取回调或返回承诺.采取回调看起来像:

function write(pageText, elementId, delay, callback)
{
  var element = document.getElementById(elementId);
  var charCount=0;

  var interval = setInterval(function(){
    if(charCount>pageText.length)
    {
      clearInterval(interval);
      callback();
    }
    else
    {
      element.innerHTML = pageText.substr(0,charCount++);
    }
  }, delay);
}
Run Code Online (Sandbox Code Playgroud)

callback当完整pageText写入时会调用element.请注意,它还会在完成后清除间隔计时器,从而避免事件循环泄漏.

然后,您需要使用此回调链接异步调用.您可以使用以下库来非常干净地完成此操作async:

function writePassage()
{
  var passage=["message one", "message two", "... message n"];
  async.series(passage.map(function(text){
    return function(done){
      write(text, 'someRandomDiv', 100, done);
    };
  }));
}
Run Code Online (Sandbox Code Playgroud)

但手工做也不是那么麻烦:

function writePassage()
{
  var passage=["message one", "message two", "... message n"];

  var writeOne = function() {

    if (!passage.length) return;

    var text = passage.shift();

    write(text, 'someRandomDiv', 100, writeOne);
  }

  // Kick off the chain.
  writeOne();
}
Run Code Online (Sandbox Code Playgroud)

那只是异步递归.欢迎使用JavaScript.:)

基于承诺的解决方案也可以非常干净.首先,您需要从以下方面返回承诺write:

function write(pageText, elementId, delay)
{
  return new Promise(resolve) {
    var element = document.getElementById(elementId);
    var charCount=0;

    var interval = setInterval(function(){
      if(charCount>pageText.length)
      {
        clearInterval(interval);
        resolve();
      }
      else
      {
        element.innerHTML = pageText.substr(0,charCount++);
      }
    }, delay);
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过减少创建一系列承诺:

function writePassage()
{
  var passage=["message one", "message two", "... message n"];

  passage.reduce(function(chain, text) {
    return chain.then(function(){
      return write(text, 'someRandomDiv', 100, writeOne);
    });
  }, Promise.resolve());
}
Run Code Online (Sandbox Code Playgroud)