【问题标题】:Returning an array from the JavaScript OS.File.DirectoryIterator从 JavaScript OS.File.DirectoryIterator 返回一个数组
【发布时间】:2014-12-27 08:25:48
【问题描述】:

我开始使用 OS.File 模块中的 OS.File.DirectoryIterator 编写一些脚本。我已经得到了以下代码块......有点。

我要做的是遍历给定的目录(它有 4 个子目录)并将子目录的名称放入一个数组中。问题是数组按预期填充,但在 promise 构造之外不可用。

诚然,我对 promises 缺乏经验,所以我确信问题在于我是如何构建它的(从 OS.File.DirectoryIterator 上的 MDN 页面提取)。所以我的问题是:为什么数组可以在 Promise 内访问,但不能在 Promise 外访问?

var iterator = new OS.File.DirectoryIterator(PathToDir);
var subDirNames = [];

var promise = iterator.forEach(
   function(entry) {
      subDirNames.push(entry.name);
   }
);

promise.then(
   function(success) {
      iterator.close();
      console.log("--> "+subDirNames[1]); \\Array element 1 display in console fine.
      return subDirNames;
   },
   function(failure) {
      console.log("--> Error: "+failure);
   }
);
console.log("--> "+subDirNames[1]); \\Array element 1 displays as undefined.

【问题讨论】:

标签: javascript arrays promise


【解决方案1】:

在特殊情况之外,JavaScript 中的并发模型如下:

  • 代码始终从第一行同步运行到最后一行。事情一一发生。
  • 涉及 I/O 的所有内容(如文件系统或 Web 访问)都会立即返回,而是交替报告完成 - 通过回调或返回承诺。
  • 解包承诺是在不同的范围内完成的。

所以,在一行中你不能像你一样同步访问subDirNames,因为 I/O 还没有执行,而是你可以检测 I/O 何时完成承诺。幸运的是,这是一个生成器插件,因此您也有其他选择。

直截了当的承诺方法

链接承诺:

var p2 = promise.then(... /* your iterator.close() code here */); // new promise
//... run more code
// when you need to access subDirNames
p2.then(Function(names){
    console.log(names[1]); // will always work. 
});

这是并发模型 - 它非常有用,它避免了很多线程问题。

发电机

由于您直接为 Firefox 开发东西,因此您没有浏览器兼容性问题,并且可以使用 EcmaScript 6 的可用功能。我们可以使用生成器来暂停执行函数并等待结果 - 首先是一个小帮手:

function async(gen){ "use strict"; // this takes a generator
    gen = gen(); // starts it
    return Promise.resolve().then(function cont(a){
        var n = gen.next(a); // gets the next element
        if(n.done) return Promise.resolve(n.value); // a `return` 
        if(!n.value.then) return cont(n.value); // yield plain value
        return n.value.catch(gen.throw.bind(gen)).then(cont);
    });
}

您可以从 之类的库中获取此功能,而不是您想要的(它们执行速度更快,但这在这里并不真正相关)。

这会让你做这样的事情:

async(function*(){
    var iterator = new OS.File.DirectoryIterator(PathToDir);
    // optimally you'd do yield* iterator but this API predates modern iterators
    var subDirNames = [];
    yield iterator.forEach(function(entry) { // note the yield
        subDirNames.push(entry.name);
    });
    iterator.close();
    console.log(subDirNames[1]); // will log correctly
});

【讨论】:

  • @benjamin - 感谢您的详细解释和示例。这让我明白了一些事情。我能够使用您的示例来做我需要的事情。但是,这又提出了一个问题……在您的链示例中, p2.then 是否在每次调用时实际执行承诺?换句话说,如果我调用 p2.then 每次我需要对数组 subDirNames 做某事,是否正在执行另一个目录迭代?
  • @user3402292 可以在 StackOverflow 中随意提问。最好每个线程保留一个问题,因此您可能想要打开一个新问题。如果你觉得这个回答可以考虑accepting an answer
猜你喜欢
  • 2015-09-24
  • 2020-09-03
  • 2017-05-02
  • 1970-01-01
  • 2016-10-16
  • 1970-01-01
  • 2017-08-07
  • 2022-01-02
  • 2011-06-23
相关资源
最近更新 更多