3

我正在尝试为流量控制目的实现一系列函数,但得到了意想不到的结果。我需要检查文件是否存在,结果是 Node 启动的 shell cmd,在 5000 毫秒的过程中。使用 Mixu 的Node book,我正在使用一个系列函数来进行顺序执行(第 7.2.1 节)。根据 Node 书籍,如果您需要将一个结果输入另一个结果,则此模式是合适的,但似乎并非如此,因为final()在参数函数的任何回调返回之前执行。

下面应该是重现我所看到的内容所需的所有代码。

预期输出:(假设正在检查的文件是在 < 1000 毫秒内创建的)

1347312844082

1347312845082

1347312846083

1347312847082

1347312848082

<--console.log() 在系列函数的最后一个参数函数中的最后一个真结果。

实际输出

1347312844082
1347312845082
1347312846083
1347312847082
1347312848082
false <-- 在系列参数回调之前评估系列函数的最后一个参数函数。
真的
真的
真的
真的
真的

我的睡眠函数的回调(包含fs.check调用)

  • args由于系列函数的参数都被 slice.call(arguments) 调用而被推回
  • 然后转到最后一个函数,
  • 最后处理回调。

但这似乎与 Node 书中描述的行为相矛盾。

注意:我试图避免回归到同步调用fs.existsSync

    var outputFile = 'C:\\Some\\Valid\\Path\\foo.txt';
    var successCheck = false;
    series([
            sleep(1000, function () {
                printTime();
                fs.exists(outputFile, function (exists) {
                    console.log(exists);
                    successCheck = exists;
                });
            }),
            /* middle three deleted for brevity */
            sleep(1000, function () {
                printTime();
                fs.exists(outputFile, function (exists) {
                    console.log(exists);
                    successCheck = exists;
                });
            }),

            sleep(1000, function () {
                printTime();
                fs.exists(outputFile, function (exists) {
                    console.log(exists);
                    successCheck = exists;
                });
            })
            ], function() {
                console.log(successCheck);
        });


    function sleep (msInterval, callback) {
        var now = new Date().getTime();
        while(new Date().getTime() < now + msInterval) {
      // do nothing
        }
        callback();
    }

    function series (callbacks, last)  {
        var results = [];
        function next() {
            var callback = callbacks.shift();
            if(callback) {
                callback(function() {
                    results.push(Array.prototype.slice.call(arguments));
                    next();
                });
            } else {
                last(results);
            }
        }

        next();
    }

    function printTime () { var now = new Date().getTime(); console.log(now); }
4

1 回答 1

2

我看到你的代码有几个问题。首先,你对“睡眠”的态度完全被打破了。

JavaScript(以及 Node)是一种单线程、事件驱动的语言。如果你做了任何阻止的事情,你就会阻止整个程序。

您的函数通过旋转直到几毫秒过去sleep来阻止整个程序。msInterval

这正是正在发生的事情:

  • 首先设置一些变量。
  • 有一个呼叫series。为了向它传递参数,我们必须评估这些参数。
  • sleep在下一行调用。
  • sleep旋转 1000 毫秒。
  • sleep调用它的callback.
  • 回调将内容打印到控制台,发出异步 I/O 请求并返回。
  • sleep返回未定义
  • 调用下一个sleep调用;重复最后 5 个步骤。
  • ... 5 秒后,所有调用sleep都已完成。您现在有一个如下所示的数组:

    [undefined, undefined, undefined, undefined, undefined]
    

    因为sleep不返回任何东西。

  • 现在series可以使用参数调用未定义的数组和函数。
  • results被实例化。
  • next被调用。
  • 数组中的第一个未定义被移出。
  • 由于undefined是假的,所以跳转到else分支。
  • last使用空数组调用。(我们从不放任何东西results
  • last回调打印successCheck, 即,false并返回。
  • 至此,同步代码已经完成。
  • JavaScript 开始事件循环的下一次迭代。您之前发出的 I/O 请求此时可能已完成,因此fs.exists回调按照它们完成的顺序调用(可能是,但不一定是发出它们的顺序)。
  • 回调打印到控制台并设置successCheck(实际上永远不会再次读取)。
  • 程序结束。

 

如何修复它

永远,永远,永远在while循环中旋转。你可以这样重写sleep

function sleep(ms, cb) {
    return function(done) {
        setTimeout(function() {
            cb(done);
        }, ms);
    }
}

在这里,我们返回一个稍后将被调用的函数。这样,传递给的数组就被内部函数series填充了。sleep当你调用它sleep时,实际上还没有发生任何事情

series调用第一个数组元素时,它实际上是调用返回的匿名函数,我们已经关闭了最初传递给调用的msand 。该函数将超时设置为毫秒。什么过期,最里面的匿名函数被调用,它调用. 它将函数作为其参数传递,这实际上是来自'的匿名函数,它推入并调用.cbsleepmscbdoneseriesnextresultsnext

因为您的系列的下一步直到上一步指示完成后才开始,您必须done从该步骤的函数调用回调:

sleep(1000, function (done) {
    printTime();
    fs.exists(outputFile, function (exists) {
        console.log(exists);
        successCheck = exists;
        done();
    });
});

改变你的方法

当然,您真正想要解决问题的方式(“创建此文件后我该怎么做?”)不是通过轮询fs.exists

相反,使用文件系统更改通知! fs.watch允许您监听文件或文件夹的更改。

var watcher = fs.watch('C:\\Some\\Valid\\Path\\', function(e, filename) {
    if (filename == 'foo.txt') {
        // success!
        watcher.close(); // stop watching for changes
    }
});
于 2012-09-10T23:55:50.860 回答