Nodejs http.get异步带来的困扰

Nodejs http.get异步带来的困扰

webot.set(‘news’,{
pattern: /new.*/i,
handler:function(info){
news = [];
http.get(address, function(res){
var data = ‘’;

    res.on('data' , function(d){
        data += d;
    }).on('error',function(err){
    console.log(err.message);
    });

    res.on('end' , function(){
    //分析HTML找到需要的内容,并赋给news
    var $ = cheerio.load(data);
    $('table').eq(2).find('table').eq(1).find('tr').slice(1,13)
    .each(function(index,ele){
        news[index] = {
            title:this.find('a').first().text(),
            url:this.find('a').attr('href')
        };
    })    
    }).on('error',function(err){
        console.log(err.message);
    });
}).on('error', function(err){
    console.log(err.message);
});
return news;

} });

用之前公布的微信ROBOT做一个微信机器人。分析HTML然后返回结果,作一个简单的爬虫。但是news被直接返回了,还没等到http.get执行完,这个时候应该怎么办,有什么异步返回方法么?


5 回复

在使用 Node.js 的 http.get 方法时,经常会遇到异步操作带来的困扰,特别是在处理依赖于异步操作的结果时。在你提供的代码中,news 数组是在异步请求完成之前就被直接返回了,因此它始终是空的。为了解决这个问题,我们可以使用回调函数或者 Promise 来管理异步操作。

使用回调函数

首先,我们可以通过回调函数来处理异步操作的结果。下面是修改后的代码:

const http = require('http');
const cheerio = require('cheerio');

webot.set('news', {
  pattern: /new.*/i,
  handler: function (info, cb) {
    const news = [];
    http.get(address, function (res) {
      let data = '';

      res.on('data', function (d) {
        data += d;
      }).on('error', function (err) {
        console.log(err.message);
      });

      res.on('end', function () {
        // 分析 HTML 找到需要的内容,并赋给 news
        const $ = cheerio.load(data);
        $('table').eq(2).find('table').eq(1).find('tr').slice(1, 13)
          .each(function (index, ele) {
            news[index] = {
              title: $(this).find('a').first().text(),
              url: $(this).find('a').attr('href')
            };
          });
        // 将结果通过回调函数传递出去
        cb(null, news);
      }).on('error', function (err) {
        console.log(err.message);
        cb(err, null);
      });
    }).on('error', function (err) {
      console.log(err.message);
      cb(err, null);
    });
  }
});

// 使用回调函数获取新闻数据
webot.on('news', function (info, cb) {
  webot.execute('news', info, function (err, result) {
    if (err) {
      console.error(err);
    } else {
      console.log(result); // 输出解析后的新闻数据
    }
  });
});

使用 Promise

另一种更现代的方法是使用 Promise,这可以使得代码更加简洁和易于理解。以下是使用 Promise 的示例:

const http = require('http');
const cheerio = require('cheerio');

webot.set('news', {
  pattern: /new.*/i,
  handler: function (info) {
    return new Promise((resolve, reject) => {
      const news = [];
      http.get(address, function (res) {
        let data = '';

        res.on('data', function (d) {
          data += d;
        }).on('error', function (err) {
          console.log(err.message);
          reject(err);
        });

        res.on('end', function () {
          // 分析 HTML 找到需要的内容,并赋给 news
          const $ = cheerio.load(data);
          $('table').eq(2).find('table').eq(1).find('tr').slice(1, 13)
            .each(function (index, ele) {
              news[index] = {
                title: $(this).find('a').first().text(),
                url: $(this).find('a').attr('href')
              };
            });
          resolve(news);
        }).on('error', function (err) {
          console.log(err.message);
          reject(err);
        });
      }).on('error', function (err) {
        console.log(err.message);
        reject(err);
      });
    });
  }
});

// 使用 Promise 获取新闻数据
webot.on('news', async function (info) {
  try {
    const result = await webot.execute('news', info);
    console.log(result); // 输出解析后的新闻数据
  } catch (err) {
    console.error(err);
  }
});

在这两种方法中,我们都确保了在异步请求完成之后再返回结果,从而避免了直接返回尚未完成的数据的问题。


看看async库

正常执行顺序就是这样的, 常用的方案是在 handler 后边传一个回调函数 (info, callback) get 请求完成以后调用回调函数, 把后边的操作写在回调函数函数体里边

我看了一下源码的例子,他在里面用了中间件一层一层的处理,只要传一个next,调用后交给最后处理的函数就可以。

在处理 Node.js 中的异步操作时,http.get 是一个典型的异步调用。在你的代码中,news 变量被立即返回,而此时 http.get 还没有完成数据获取。这会导致 news 为空。

为了解决这个问题,你可以使用回调函数或 Promise 来处理异步操作。以下是使用 Promise 的示例代码:

const http = require('http');
const cheerio = require('cheerio');

webot.set('news', {
  pattern: /new.*/i,
  handler: function (info) {
    return new Promise((resolve, reject) => {
      http.get(address, function (res) {
        let data = '';

        res.on('data', function (d) {
          data += d;
        }).on('error', function (err) {
          console.log(err.message);
          reject(err);
        });

        res.on('end', function () {
          try {
            const $ = cheerio.load(data);
            const news = [];

            $('table').eq(2).find('table').eq(1).find('tr').slice(1, 13).each(function (index, ele) {
              news.push({
                title: $(this).find('a').first().text(),
                url: $(this).find('a').attr('href')
              });
            });

            resolve(news);
          } catch (err) {
            reject(err);
          }
        });
      }).on('error', function (err) {
        console.log(err.message);
        reject(err);
      });
    });
  }
});

// 使用示例
webot.handle({ message: 'news' }).then(result => {
  console.log(result);
}).catch(error => {
  console.error(error);
});

在这个示例中,我们使用 Promise 包装了 http.get 操作,并在 http.get 完成后通过 resolve 返回结果。这样,你可以确保在 news 数据准备好后再进行后续处理。

回到顶部