如何在NodeJS createServer中调用模块函数

时间:2016-03-12 08:47:18

标签: javascript node.js

我有两个js文件screenshot.js和main.js,我想将screenshot.js中的JSON返回给main.js,但是当你运行console.log时它没有返回结果,在screenshot.js文件中this.result)你在控制台中看到结果但是当你在main.js文件中调用它时结果是空的,怎么能解决这个问题。

这是我的代码。

screenshot.js

module.exports={
result: '',
run: function(url,w,h){
var phantom=require('phantom');
phantom.create().then(function(ph){
    ph.createPage().then(function(page){
        page.property('viewportSize',{width:w,height:h}).then(function(){
            page.open('http://' + url + '/').then(function(status){
                page.property('onLoadFinished').then(function(){
                    console.log(status);
                    if (!(status == 'success')){
                         this.result={'image':'no'};
                         this.result=JSON.stringify(this.result);
                        //  console.log(this.result);
                            page.close();
                    } else {
                this.result=page.renderBase64('jpeg').then(function(img){
                                this.result={'image': img};
                                this.result = JSON.stringify(this.result);
                                //  console.log(this.result);
                                page.close();
                        });
                    }
                });
            });
        });
    });
});
return this;
},
get: function(){
return this.result;
}
}

main.js

var http = require( 'http' );
var parsing = require( 'url' );
var screenshot = require( './screenshot' );
http.createServer( function( req, res ) {
var url, img, w, h, query_object, result;
url = req.url;
url = url.replace( '/', '' );
url = url.trim();
if ( !( url == 'favicon.ico' ) ) {
  console.log( url );
  query_object = parsing.parse( req.url, true ).query;
  console.log( query_object );
  res.writeHeader( 200, { "Content-Type": "text/html" } );
  w = parseInt( query_object.width );
  h = parseInt( query_object.height );
  result = screenshot.run( url, w, h ).get();
  console.log( result );
  res.end();
}
}).listen( 80, '127.0.0.1' );

console.log( 'server isn running....' );

1 个答案:

答案 0 :(得分:1)

您的操作是异步的。在完成之前,您无法获取结果。您在异步操作完成之前很久就调用.get()。您需要从.run()返回一个承诺并使用.then(),而不是将结果存储在实例数据中而无法告诉它什么时候准备好了。

作为一般规则,每当你获取在异步回调中获得的结果并将其分配给某个更高范围的变量时,这是一个重要的警告信号,表明你可能做错了,因为更高范围内的代码不知道该值何时有效。相反,您需要使用异步回调中的值,从该回调中调用某个函数并将该函数传递给值或在promise中返回值,以便调用者可以将其作为promise的履行值(这就是我改变你的代码的原因。)

这是一个重写版本,它返回一个promise并将结果作为promise的履行值返回:

module.exports = {
    run: function (url, w, h) {
        var phantom = require('phantom');
        return phantom.create().then(function (ph) {
            ph.createPage().then(function (page) {
                page.property('viewportSize', {
                    width: w,
                    height: h
                }).then(function () {
                    page.open('http://' + url + '/').then(function (status) {
                        page.property('onLoadFinished').then(function () {
                            console.log(status);
                            if (status != 'success') {
                                page.close();
                                return JSON.stringify({'image': 'no'});
                            } else {
                                return page.renderBase64('jpeg').then(function (img) {
                                    page.close();
                                    return JSON.stringify({'image': img});
                                });
                            }
                        });
                    });
                });
            });
        });
    }
}

稍后,我会发布一个更好的方法来写这个,但不会使用这么多的承诺嵌套。

不是调用.get(),而是使用返回的promise,如下所示:

var http = require( 'http' );
var parsing = require( 'url' );
var screenshot = require( './screenshot' );
http.createServer( function( req, res ) {
    var url, img, w, h, query_object, result;
    url = req.url;
    url = url.replace( '/', '' );
    url = url.trim();
    if ( !( url == 'favicon.ico' ) ) {
      console.log( url );
      query_object = parsing.parse( req.url, true ).query;
      console.log( query_object );
      res.writeHeader( 200, { "Content-Type": "text/html" } );
      w = parseInt( query_object.width );
      h = parseInt( query_object.height );
      screenshot.run( url, w, h ).then(function(result) {
          console.log( result );
          res.end();
      });
    }
}).listen( 80, '127.0.0.1' );

console.log( 'server isn running....' );

我自己没有测试方法,但这应该是run()方法的较少嵌套版本。这在可能的情况下使用链接,只有在跟随.then()处理程序需要访问先前结果时才进行嵌套。

module.exports = {
    run: function (url, w, h) {
        var phantom = require('phantom');
        return phantom.create().then(function (ph) {
            return ph.createPage();
        }).then(function (page) {
            // nest other calls here so they all have access to the page argument
            return page.property('viewportSize', {width: w, height: h }).then(function () {
                return page.open('http://' + url + '/');
            }).then(function (status) {
                return page.property('onLoadFinished').then(function() {return status;});
            }).then(function (status) {
                console.log(status);
                if (status != 'success') {
                    page.close();
                    return JSON.stringify({'image': 'no'});
                } else {
                    return page.renderBase64('jpeg').then(function (img) {
                        page.close();
                        return JSON.stringify({'image': img});
                    });
                }
            });
        });
    }
}

注意:我认为您还缺少在出现错误时调用page.close()的错误处理。

这是一个添加了closePage()错误处理的版本,因此无论何时打开页面,无论我们如何保留此代码,即使发生错误,它也会被关闭:

module.exports = {
    run: function (url, w, h) {
        var phantom = require('phantom');
        return phantom.create().then(function (ph) {
            return ph.createPage();
        }).then(function (page) {
            var pageOpen = false;

            function closePage(val) {
                if (pageOpen) {
                    page.close();
                }
                return val;
            }

            // nest other calls here so they all have access to the page argument
            return page.property('viewportSize', {width: w, height: h }).then(function () {
                return page.open('http://' + url + '/');
            }).then(function (status) {
                pageOpen = true;
                return page.property('onLoadFinished').then(function() {return status;});
            }).then(function (status) {
                console.log(status);
                if (status != 'success') {
                    return JSON.stringify({'image': 'no'});
                } else {
                    return page.renderBase64('jpeg').then(function (img) {
                        return JSON.stringify({'image': img});
                    });
                }
            }).then(function(closePage), function(err) {
                closePage();
                throw err;
            });
        }):
    }
}