【问题标题】:Why does this async IO using promises generate a zero length file?为什么这个使用 Promise 的异步 IO 会生成一个长度为零的文件?
【发布时间】:2014-10-31 00:58:13
【问题描述】:

谁能弄清楚这段代码有什么问题?我正在尝试将少量字节写入文件,但我得到的只是一个零长度文件,没有报告任何错误。

我正在尝试在 node.js 中使用异步文件 IO 和 bluebird 承诺将一些数据写入本地文件。我已经成功地编写了这个函数的同步版本和使用回调的异步版本。但是,因为回调版本是嵌套地狱并且有各种各样的错误处理问题并且不是很容易维护,所以我想我会尝试使用promises的版本,因为这应该是它的强项(更好的错误处理,更少的嵌套,更容易排序异步操作)。

不幸的是,promise 版本只会生成零长度文件。这是 Promise 版本的代码:

// at initialization time
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));


    // code in a function
    var header = new Buffer('[temperatures] {"formatVersion": "1", "fields": ["t", "atticTemp", "outsideTemp"]}\r\n');
    filename += ".new";
    console.log("async write started");
    var fd;
    fs.openAsync(filename, "w", 438).then(function(ffd) {
        fd = ffd;
        return fs.writeAsync(fd, header, 0, header.length, null);            
    }).then(function(args /* [written, buffer] */) {
        var written = args[0];
        console.log("bytes written =" + written);
        if (written !== header.length) {
            console.log("not all data written");
            throw new Error("not all data written");
        }

        // lots more data to write here

        return fs.closeAsync(fd);
    }).then(function() {
        fd = null;
        console.log(" async write finished");
    }).catch(function(e) {
        // if (fd) fs.closeAsync(fd);
        console.log(e, "data.writeData() - error writing data (new format)");
    });

我已经完成了我知道如何进行调试的所有工作。所有预期的console.log() 错误消息都以所需的顺序出现。我已经验证了所有返回值和参数。不会以任何方式报告错误。在再次运行之前,我已经删除了以前的文件。我在我的回调版本中使用了相同的参数和文件名,效果很好(这似乎排除了文件权限问题)。我已经重新启动了计算机(顺便说一下,这是一个 Raspberry Pi)。

我被难住了。我认为这一定是我在使用 Promise 时做错了一些愚蠢的事情,但我一辈子都看不出有什么问题。

【问题讨论】:

  • +1 使用蓝鸟 :)
  • 这对我有用。你能让它更具重现性吗?
  • @simonzack - 我得看看能否在独立的 node.js 应用程序中重现它。
  • @simonzack - 嗯。它适用于同一平台上的独立 node.js 应用程序。好的,显然代码在结构上没有任何问题。现在,我想知道可能导致问题的应用程序上下文是什么?此代码似乎对其他任何内容没有任何依赖关系。传入的唯一数据是创建的文件名,因此这不是垃圾。我已经注释掉了这个函数中的所有其他代码并且没有改变。我没有看到任何意外的全局变量(也在严格模式下运行)。这很奇怪。还有什么要寻找的想法吗?

标签: javascript node.js raspberry-pi promise bluebird


【解决方案1】:

好的,我想通了。在应用程序的正常操作中调用此函数时,它可以正常工作。而且,如果我查看它在应用程序仍在运行时生成的文件,则该文件很好。

但是(这就是问题所在),当应用程序退出时,我也在调用此函数。而且,你猜怎么着,你不能在退出事件处理程序中使用这些类型的异步操作而不会导致问题。它会创建新的空文件,然后应用程序退出,这就是剩下的东西(只是磁盘上新创建的空文件)。

这个特定的函数有一个参数传入是否需要同步或异步进行写入(仅出于这个原因),我还没有编写新的承诺样式代码的同步部分(我已经编写了同步我使用的其他代码版本的版本)。

奇怪的谜团解开了。而且,这很愚蠢。与承诺没有直接关系,但这是一个异步问题。

另一个谜团是为什么我的异步代码版本,但使用回调而不是承诺没有显示这个问题?显然,它在进程退出之前完成了它的工作,但承诺版本没有。

【讨论】:

  • 有趣。如果您使用 setTimout 强制将文件写入另一个事件线程,那么在回调版本中会发生什么?超时延迟的长度重要吗?
  • 对于这项运动,您是否愿意运行 Bluebird 的 Zalgo 版本,看看它是否表现出与此处的回调相同的行为? Promise 提供了回调不提供的异步保证,但 Zalgo 构建删除了它们。
  • (另外,这里要做的适当的事情可能是阻止和使用函数的同步版本,因为它位于应用程序退出处理程序上)
  • @BenjaminGruenbaum - 我将如何在我的树莓派上运行 Zalgo 构建?是的,我最终必须编写此保存功能的异步和同步版本,以便我可以在应用退出时使用同步版本,在正常应用运行期间使用异步版本。有点痛苦,但我不知道有什么其他方法可以解决我的问题,除非我一直使用我不想这样做的同步版本。
  • 听起来……令人沮丧。我会看看我是否能想出一个聪明的方法来只写一次代码。您可以控制关​​闭您的应用吗?
猜你喜欢
  • 1970-01-01
  • 2020-01-28
  • 1970-01-01
  • 2014-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-15
  • 2019-05-04
相关资源
最近更新 更多