简体   繁体   English

如何在 NodeJS createServer 内部调用模块函数

[英]How to call module function inside NodeJS createServer

I have two js file screenshot.js and main.js, I want to return JSON from screenshot.js to main.js, but it didn't return result, in screenshot.js file when you run console.log(this.result) you see result in console but when you call it in main.js file the result is empty, how can solve this problem.我有两个 js 文件 screenshot.js 和 main.js,我想将 JSON 从 screenshot.js 返回到 main.js,但是当你运行 console.log(this.result) 时它没有返回结果,在 screenshot.js 文件中) 您在控制台中看到结果,但是当您在 main.js 文件中调用它时,结果为空,如何解决此问题。

This is my code.这是我的代码。

screenshot.js截图.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....' );

Your operation is async.您的操作是异步的。 You can't fetch the result until it's done.在完成之前您无法获取结果。 You are calling .get() long before your async operations are done.You need to return a promise from .run() and use .then() on that, not store the result in the instance data with no way to tell when it's ready.您在异步操作完成之前很久就调用了.get()您需要从.run()返回一个 promise 并在其上使用.then() ,而不是将结果存储在实例数据中,无法判断它何时准备好。

As a general rule, any time you are taking a result that is obtained inside an async callback and you are assigning it to some higher scoped variable, that's a major warning sign that you may be doing something wrong because code in higher scopes will have no idea when that value is valid.作为一般规则,任何时候您在异步回调中获取一个结果并将其分配给某个更高范围的变量时,这是一个主要的警告信号,表明您可能做错了什么,因为更高范围内的代码将没有当该值有效时的想法。 Instead, you need to either use the value inside the async callback, call some function from within that callback and pass that function the value or return the value in a promise so it can be consumed by the caller as the fulfilled value of the promise (that's what I changed your code to be below).相反,您需要使用异步回调中的值,从该回调中调用某个函数并将该值传递给该函数,或者在承诺中返回该值,以便调用者可以将其作为承诺的已履行值(这就是我将您的代码更改为下面的内容)。

Here's a rewritten version that returns a promise and returns the result as the fulfilled value of the 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});
                                });
                            }
                        });
                    });
                });
            });
        });
    }
}

In a bit, I will post a better way to write this too that doesn't use so much promise nesting.稍后,我将发布一个更好的方法来编写它,它不会使用太多的承诺嵌套。

The, instead of calling .get() , you just use the returned promise like this:而不是调用.get() ,您只需使用返回的承诺,如下所示:

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....' );

I don't have a means of testing this myself, but this should be a less nested version of your run() method.我自己没有办法对此进行测试,但这应该是run()方法的嵌套较少的版本。 This uses chaining where possible, only nesting when following .then() handlers need access to prior results.这在可能的情况下使用链接,仅在跟随.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});
                    });
                }
            });
        });
    }
}

Note: I think you are also missing error handling that calls page.close() in case of errors.注意:我认为您还缺少在发生错误时调用page.close()的错误处理。

Here's a version with error handling for closePage() added so anytime a page was opened, it will be closed no matter how we leave this code, even if errors occurred:这是一个添加了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;
            });
        }):
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM