缓存函数的结果

时间:2016-03-13 20:04:35

标签: javascript node.js

如何在节点中的变量中存储异步函数的结果?例如,我想解析一个网站并获得一些信息,但我不想经常请求数据,我想只获得一次所有页面。这是代码:

var cheerio = require('cheerio');
var request = require('request');

function SiteParser() {
  const SITE = 'http://www.anywebsite.com';

  // variable for caching html
  var $ = getBody();

  function getBody(SITE){
    // request html
    request(SITE, function(error, response, html) {
      if (!error && response.statusCode == 200) {
        return cheerio.load(html);
      }
      else {
        throw new Error('Could not parse web site\nError text: ' + error);
      }
    })
  }

  //declaration of class methods using cached html
  this.getCategories = function() {};
  this.getNews = function() {};
}

当我打电话给班级的方法时,我怎么能确定会收到回复? 或者这是一种不好的做法?

1 个答案:

答案 0 :(得分:0)

请注意,var $ = getBody();无法正常工作,因为getBody不会返回任何内容。内部回调会返回一些内容,但返回值永远丢失。此外,该回调是异步调用的,因此您无法通过var $ = getBody();获取它,因为getBody在执行回调之前完成。

因此,这是解决该问题的快捷方法。构造函数将可选的回调函数作为参数:

function SiteParser(onready) {
  const SITE = 'http://www.anywebsite.com';

  // variable for caching html
  var $;
  var that = this; // maintain reference to this instance of SiteParser

  function getBody(SITE){
    // request html
    request(SITE, function(error, response, html) {
      if (!error && response.statusCode == 200) {
        $ = cheerio.load(html); // store the result
        that.ready() // notify client that html has been retrieved
      }
      else {
        throw new Error('Could not parse web site\nError text: ' + error);
      }
    })
  }

  //declaration of class methods using cached html
  this.getCategories = function() {
      if ($ === undefined) throw new Error('Not ready yet');
      // extract categories from $ and return them
  };
  this.getNews = function() {
      if ($ === undefined) throw new Error('Not ready yet');
      // extract news from $ and return it
  };
  this.ready = onready || function() {}; // callback for being notified
}

现在你可以写:

parser = new SiteParser;
parser.ready = function () {
    var cats = parser.getCategories();
    // ...etc
};

或者:

parser = new SiteParser(function () {
    var cats = parser.getCategories();
    // ...etc
});

无极

即使尚未检索到HTML,上述代码也会公开 getCategories getNews 方法。这不太好。

使用promise概念,您可以通过仅在所有准备就绪时提供SiteParser实例来改进。以下是您可以与promise for nodejs一起使用的一些(未经测试的)代码:

var Promise = require('promise');

// SiteParser now needs to be given the HTML in the constructor:
function SiteParser(html) {
    var $ = $cheerio.load(html)

    //declaration of class methods using cached html
    this.getCategories = function() {
        // extract categories from $ and return them
    };
    this.getNews = function() {
        // extract news from $ and return it
    };
}

// a separate Promise object takes care of the retrieval:
function promiseSiteParser() {
  const SITE = 'http://www.anywebsite.com';

  return new Promise(function (resolve, reject) {
    // request html
    request(SITE, function(error, response, html) {
      if (!error && response.statusCode == 200) {
        resolve(new SiteParser(html));
      }
      else {
        reject(error);
      }
    })
  });
}

promiseSiteParser().then(function (parser) {
    var cats = parser.getCategories();
    // ...etc
}, function (error) {
    throw new Error('Could not parse web site\nError text: ' + error);
});