如何从Node.js中的嵌套函数内部向eventListener发出(javascript范围问题)

时间:2012-03-09 09:51:18

标签: events node.js scoping

我正在编写下面的代码,一次解析一个站点API,而不是告诉事件队列它已准备好下一个要解析的对象。我有问题,因为我还是新的javascript范围,并希望从SiteParser发出或调用emitForNext函数。我似乎无法将emitForNext带入错误回调的范围。

   function SiteParser(){
        this.emitForNext = function  (message) {
            this.emit("next", message);
        };

        this.pullJSON = function (path, processJSON) { //processJSON is a callback function    
            var options = {
                host: 'www.site.com',
                port: 80,
                path: path
            }

            //console.log("... processing "+path); 

            //pulls the entire json request via chunks
            http.get(options, function  (res) {
                var resJSON = ''; //stores the comment JSON stream given in the res
                res.on('data',  function (chunk) {
                    resJSON+=chunk;   
                });  
                res.on('end', function () {
                    var obJSON = (JSON.parse(resJSON));  

                    if (obJSON.hasOwnProperty("error")){ 
                        console.log(obJSON);
                        console.log('... ', path, ' does not exist');
                        //
                        //NEED A NEXT EVENT EMMITER HERE NEED TO FIGURE OUT SCOPE
                        //
                        //   
                    } else {
                        processJSON(obJSON); //call the callback function
                    }
                }) ;
            }).on('error', function  (e) {
                emitForNext("got error: " + e.message);
            });
        };
    }

3 个答案:

答案 0 :(得分:4)

JavaScript具有函数作用域,如果使用var关键字声明变量,它将是当前函数的本地变量。当您访问变量时,它将查看范围链,该范围链包含当前函数,它的父函数,....尝试:

function one() {
    var foo = 'foo';

    function two() {
        console.log(foo) // undefined. I'll explain this
        var foo = 'bar';
        console.log(foo) // bar
    }

    two()
    console.log(foo) // foo
}
one()

大多数时候我们在函数的开头定义变量,因为函数体中定义的变量会被提升。基本上,它意味着它在整个函数中都可用,甚至在它被定义之前,但在这种情况下,它的值是undefined

例如,如果未定义变量,我们通常会获得ReferenceError,但在下面的代码段中,console.log()只打印undefined

function foo() {
     console.log(bar);
     if (0) {
         var bar = 'bar';
     }
     console.log(bar);
}

因此,通常的做法是,当你编写长函数时,将它映射到self。

function SiteParser() {
    var self = this;
    // ...
    .error('error', function(err) {
        self.emitForNext("got " + err.message);
    })
}

你不应该在构造函数中编写所有方法,它只在我们想要隐私时才有用,但在这种情况下你最好使用原型。

把它放在一起,我会写:

var SiteParser = function() {};

SiteParser.prototype.emitForNext = function(message) {
    this.emit("next", message);
};

SiteParser.prototype.pullJSON = function(path, processJSON) { 
    var self    = this,
        options = {
            host: 'www.site.com',
            port: 80,
            path: path
        };

    http.get(options, function(res) {
        // ...
    }).on('error', function  (e) {
        self.emitForNext("got error: " + e.message);
    });
};

答案 1 :(得分:2)

为了能够访问emitForNext,您需要致电self.emitForNext,其中self指向您的SiteParser实例。

像这样:

function SiteParser(){

    this.emitForNext = function  (message) {

        this.emit("next", message);

    };



    this.pullJSON = function (path, processJSON) { //processJSON is a callback function    

        var options = {

            host: 'www.site.com',

            port: 80,

            path: path

        };



        var self = this;



        //console.log("... processing "+path); 



        //pulls the entire json request via chunks

        http.get(options, function  (res) {

            var resJSON = ''; //stores the comment JSON stream given in the res

            res.on('data',  function (chunk) {

                resJSON+=chunk;   

            });  

            res.on('end', function () {

                var obJSON = (JSON.parse(resJSON));  



                if (obJSON.hasOwnProperty("error")){ 

                    console.log(obJSON);

                    console.log('... ', path, ' does not exist');





                    self.emitForNext(path + ' does not exist');

                } else {

                    self.emitForNext('Successfully parsed the response');

                    processJSON(obJSON); //call the callback function

                }

            }) ;

        }).on('error', function  (e) {

            self.emitForNext("got error: " + e.message);

        });

    };

}

然而,看起来你宁愿在回调中管理你接下来要做的事情(比如解析下一个对象),即。在processJSON的正文中。

答案 2 :(得分:1)

您需要在SiteParser本地范围内存储指向“this”对象的链接。

 function SiteParser () {
    var that = this; // store link to 'this' in local scope

    this.emitForNext = function (message) {
        this.emit("next", message);
    };

    this.pullJSON = function (path, processJSON) { //processJSON is a callback function    
        var options = {
            host: 'www.site.com',
            port: 80,
            path: path
        }

        //console.log("... processing "+path); 

        //pulls the entire json request via chunks
        http.get(options, function  (res) {
            var resJSON = ''; //stores the comment JSON stream given in the res
            res.on('data',  function (chunk) {
                resJSON+=chunk;   
            });  
            res.on('end', function () {
                var obJSON = (JSON.parse(resJSON));  

                if (obJSON.hasOwnProperty("error")){ 
                    console.log(obJSON);
                    console.log('... ', path, ' does not exist');
                    that.emitForNext();
                } else {
                    processJSON(obJSON); //call the callback function
                }
            }) ;
        }).on('error', function (e) {
            that.emitForNext("got error: " + e.message);
        });
    };
}