【问题标题】:Returning values between different scopes in javascript在javascript中的不同范围之间返回值
【发布时间】:2013-08-17 00:48:10
【问题描述】:

我是 Javascript 的新手和经验丰富的程序员,我正在努力掌握模式和设计中的概念,以便在构建应用程序时使用和处理最佳结构。 有几个领域对我来说很新,一个是掌握 Javascript 的作用域和闭包。

所以为了让你们尽可能清楚,我在这篇文章中附上了一个代码示例,希望有人可以把我的逻辑放在一边,给我一个重新思考和正确思考的指南。

我发布的代码是一个非常简单的文件系统/帮助程序库(Node.js,express)的一部分,用于扫描目录,在这些目录上运行一些条件并将结果作为映射返回数组的维度到另一个库(未发布)。您看到的代码是我当前的“测试”条件。我已经公平地评论了它。

要点:https://gist.github.com/jimmiehansson/6235613(完整视图或代码/库)

示例代码块(返回值有问题)

ApiFS.prototype.scan = function(){          
    var self = this;
    var b;
    fs.readdir(stgs.fsPath, function(err,folders){      
        if(folders.length<1) { console.log(errLog.fsEmpty); return; }       
        rslt = self.walk(folders);          
        rslt.forEach(function(itm){
            if(!self.exclusion(rslt)){ b=self.loader(stgs.fsPath,itm); }        
        });                     
    }, ioResponse);
    console.log(b); // undefined <----      
}

足够破冰了。我最大的问题:

无论我做什么,相当小的范围(提升)和关闭都会妨碍我。我目前没有使用 getter 或 setter,因为我根本不知道应该怎么做?我的逻辑完全不正确,还是我错过了一些相当基本的东西?

在代码中,您将看到 scan() 原型函数对每个返回 true/false 值或数组的函数“helper”进行一次调用。

我可以简单地通过将值返回给主 scan() 函数来使用这些值,但是为了我的生活,我不能从 fs.readdir() 函数中获取这些值以返回范围之外,例如外部ioResponse 回调。

我的逻辑缺失了什么,我该如何更好地解决这个问题(即使这意味着重建每一件事)我担心我在设计和布局这些功能的方法以及我如何处理这些值在他们之间。

非常感谢任何帮助!

【问题讨论】:

标签: javascript node.js scope closures


【解决方案1】:

这与范围无关,它与时间有关。 readdir 是异步的。它将请求发送到文件系统,然后让前面的函数继续执行。

console.log(b); 执行 之前 b=self.loader() 执行。

如果您想处理来自接受回调的函数的数据,您需要在回调中执行该工作

【讨论】:

  • 我问您是否可以详细说明一下,不是因为我认为您的回答错误,只是为了确保我能清楚地理解。我的结构(设计)和逻辑是正确的,我只是在接近值的异步函数处理错误?因此,与其在异步轮“内部”执行 forEach() 和我的自定义函数,我应该将它们放在 ioResponse 中吗?我误解了你的答案吗?谢谢
【解决方案2】:

昆汀是正确的。你肯定必须习惯节点程序的异步特性。为了清楚起见,这应该可以按您的预期工作。

ApiFS.prototype.scan = function(callback){          
    var self = this;
    var b;
    fs.readdir(stgs.fsPath, function(err, folders) {      
        if(folders.length<1) { console.log(errLog.fsEmpty); return; }

        var results = [];
        async.each(folders, function(folder) {
            if(!self.exclusion(folder)) { 
                results.push(self.loader(stgs.fsPath, itm)); 
            }            
        }, function() {});

        if(typeof(callback) == "function") {
            callback(b);
        }
    });
}

ApiFS.scan(function(files) {
    // Do something with files
});

未经测试的 Gist 重构

var fs = require('fs'),
    async = require('async'),
    _ = require('underscore'),
    path = require('path');

ApiFS = function(options){
    errLog = [];
    errLog.fsEmpty = "No existing directories or empty, cannot continue."; 
}

ApiFS.prototype.scan = function(callback) {          
    var self = this,
        results = {};
    fs.readdir(options.fsPath, function(err, folders) {
        if(folders.length<1) return callback(errLog.fsEmpty);       
        async.forEach(folders, function(folder) {
            if(!self.exclude(folder)) {
                self.loadFiles(folder, function(err, files) {
                    results[folder] = files;
                });
        }, function(err) {
            callback(err, results);
        });                     
    });     
}

ApiFS.prototype.exclude = function(folder){       
    if(options.exclude.length === 0){
        return false;
    }

    return _.contains(options.exclude, folder);
}

ApiFS.prototype.loadFiles = function(folder, callback) { 
    fs.readdir(path.join(options.fsPath, folder), function(err, files) {
        callback(err, files);
    });
};

exports = module.exports = ApiFS;

【讨论】:

  • 蒂莫西,感谢您进一步向我解释这一点。我理解您现在看到代码“示例”的意思。我想知道,如果我要从 self.loader(); 返回 b 的值; (一个数组)作为该函数“scan()”的最终返回,我会使用 forEach() 的回调来解决这个问题吗?在从 fs.readdir() 的“内部”收集的值的 fs.readdir() 之后,我对如何进行最终返回感到有些困惑——不要显得短或愚蠢。作为节点开发的第三天。例如。函数扫描(){ var b; fs.readdir(){ 迭代... b=values } 返回 b; }
  • 请记住,由于您在扫描内部使用异步函数,因此您将无法返回值,您必须提供一个回调,一旦扫描完成就会被调用。我将更新示例以向您展示回调以及如何使用它。
  • 谢谢。那太棒了,我在“代码内”视觉上更好地学习了这一点。
  • 好的,更新了。要记住的另一件事是节点中唯一的非阻塞代码是您编写的代码。我不确定 self.loader 做了什么,但如果它很慢,或者 forEach 有很多项目,整个应用程序将挂起,直到它完成处理。您可能希望使用 forEach 的异步版本,就像 async 模块中的 each 一样。 github.com/caolan/async#each
  • 感谢更新,我现在对此有了更好的理解,我只需要习惯节点喜欢处理函数之间的返回和调用的方式。这对我来说似乎更合乎逻辑。上面介绍的 forEach 使用 async.each/map 进行异步,就像我在“walk()”中所做的那样,请参阅要点:gist.github.com/jimmiehansson/6235613
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多