2016-03-12 19 views
2

我有两个js文件screenshot.js和main.js,我想从screenshot.js返回JSON到main.js,但是它没有返回结果,在screenshot.js中当你运行console.log(this.result)文件时,你会在控制台中看到结果,但是当你在main.js文件中调用它时结果为空,那么如何解决这个问题。如何调用NodeJS内部的模块函数createServer

这是我的代码。

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

你的操作是异步。完成之前您无法获取结果。在异步操作完成之前很长时间,您正在调用.get()。您需要从.run()返回一个承诺并使用.then(),但不会将结果存储在实例数据中,无法告诉它何时准备就绪。作为一般规则,任何时候当你在异步回调中获得一个结果,并且你将它分配给一个更高范围的变量时,这是一个重要的警告信号,你可能会做错某些事情,因为代码更高范围将不知道该值何时有效。相反,您需要使用异步回调中的值,从该回调中调用某个函数,并将该值传递给函数,或者将值返回给承诺,以便调用者可以将其作为承诺的履行值这就是我改变你的代码在下面)。

下面是一个重写的版本,返回一个承诺并返回结果作为承诺的履行值:

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(),你只需要使用返回承诺如下:

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; 
      }); 
     }): 
    } 
}