如何处理函数数组中的重复函数调用?

Joh*_*ohn 6 javascript

我试图按顺序执行以下函数(同步/异步)数组(避免callbackHell),以实现函数runCallbacksInSequence(我需要实现自己的函数以了解回调如何工作并避免使用Async.js)。

这是我到目前为止所拥有的。该功能runCallbacksInSequence运行良好,直到callback多次获得相同的效果为止。它停止并且不再继续执行下一个回调。理想情况下,如果callback多次获得相同的结果,则不应第二次执行,而应继续执行下一次callback

如果您有任何想法,请告诉我我做错了什么以及如何解决。 -没有承诺和异步/等待

function first(cb) {
  setTimeout(function() {
    console.log('first()');
    cb(null, 'one');
  }, 0);
}

function second(cb) {
  setTimeout(function() {
    console.log('second()');
    cb(null, 'two');
  }, 100);
}

function third(cb) {
  setTimeout(function() {
    console.log('third()');
    cb(null, 'three');
  }, 0);
}

function last(cb) {
  console.log('last()');
  cb(null, 'lastCall');
}

const cache = {};

function runCallbacksInSequence(fns, cb) {
  fns.reduce(
    function(r, f) {
      return function(k) {
        return r(function() {
          if (cache[f]) {
            return;
            // f(function(e, x) {
            //   e ? cb(e) : k(x);
            // });
          } else {
            cache[f] = f;
            return f(function(e, x) {
              return e ? cb(e) : k(x);
            });
          }
        });
      };
    },
    function(k) {
      return k();
    }
  )(function(r) {
    return cb(null, r);
  });
}

const fns = [first, second, third, second, last];

runCallbacksInSequence(fns, function(err, results) {
  if (err) return console.log('error: ' + err.message);
  console.log(results);
});
Run Code Online (Sandbox Code Playgroud)

sle*_*man 2

您的函数链接取决于对k(). 因此在你的缓存逻辑中:

if (cache[f]) {
    return;
} else {
    // ...
Run Code Online (Sandbox Code Playgroud)

链条断了。

你想要的是这样的:

if (cache[f]) {
    return k();
} else {
    // ...
Run Code Online (Sandbox Code Playgroud)

替代实施

r嵌套函数实现的问题之一是,由于多个嵌套作用域(并且同时处理多个函数( 、fk、 ) ,因此很难推理cb

一个更简单的方法是,您可以使用队列来代替尝试以编程方式构建回调地狱(这就是 async.js 所做的)。这个想法很简单,pop() 或 shift() 从数组中执行函数,直到数组为空:

function runCallbacksInSequence(fns, cb) {
    let result = [];
    let cache = {};

    function loop () {
        if (fns.length > 0) {
            let f = fns.shift(); // remove one function from array

            if (cache[f]) {
                loop(); // skip this round
                return;
            }

            cache[f] = f;
            f(function(err, val) {
                if (!err) {
                    result.push(val); // collect result
                    loop();
                }
                else {
                    // Handle errors however you want.
                    // Here I'm just terminating the sequence:
                    cb(err, result);
                }
            });
        }
        else {
            cb(null, result); // we've collected all the results!!
        }
    }

    loop(); // start the loop
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,使用此结构实现任何流逻辑都相当容易。通过控制如何跟踪结果以及每次迭代从数组中删除的函数数量,我们可以轻松实现瀑布、parallelLimit 等功能。