需要在操作完成后发送响应

Need to send response after an action has completed

我正在尝试制作一个网络爬虫,它可以爬取 IMDB 并列出电影名称和评级。这是我的 index.js 文件。 假设我正在抓取 10 部电影。然后我将抓取的结果保存在另一个文件中,比如 'message.txt'。现在我想发送此 message.txt 文件作为对任何请求的响应。但是每当我发出请求时,它总是首先向我的浏览器发送一个空文件。然后我注意到抓取的结果需要一些时间才能保存在 message.txt 文件中。我认为这是因为在 nodejs 中所有操作都是异步的。那么有没有办法在抓取完成后才发送message.txt文件呢?

var express = require('express');
var app = express();

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

app.listen(8080);
console.log('Running');


app.get('/', function(req, res) {
  console.log('Recieved the get Request');
  var i = 1;
  var count = 0;
  while (count < 10) {
    var url = 'http://www.imdb.com/title/tt' + i + '/'; 
    console.log(url);
    count = count + 1;
    i = i + 1;
    request(url, function(error, response, html) {
      if (!error) {
        var $ = cheerio.load(html);
        var title, ratings, released;
        var json = {
          title: '',
          ratings: '',
          released: ''
        };
        $('.title_wrapper').filter(function() {
          var data = $(this);
          json.title = data.children().first().text().trim();
          json.released = data.children().last().children().last().text().trim();
        });
        $('.ratingValue').filter(function() {
          var data = $(this);
          json.ratings = parseFloat(data.text().trim());
        });
        console.log(json);
        fs.appendFile('message.txt', JSON.stringify(json, null, 4) + '\n', function(err) {});   
      };
    });
  };
  res.sendFile(__dirname + '/index.js');
});

fs.appendFile('message.txt', JSON.stringify(json, null, 4) + '\n', function(err) {
//This part is executed after the process has been completed 
});   

您必须在那里进行回调,因为该部分只会在您的操作执行后调用。

我们在这里使用了回调功能,尽管在我们的例子中除了 err 之外没有任何具体的回调,但我们不需要任何其他的回调。

请尝试。

fs.appendFile() 是异步的,因此当函数 returns 时,您附加到文件的内容不会立即存在。因此,如果您想要阅读并将该文件发送给用户,您需要在提供给 fs.appendFile() 的回调中执行此操作。

app.get('/', function(req, res) {
...
        fs.appendFile(
          'message.txt',
          JSON.stringify(json, null, 4) + '\n',
          function(err) {
            if (err) {
              // Log the error and send a message to the user here
              return;
            }
            res.sendFile(__dirname + '/index.js')
          }
        );   
      };
    });
  };
});

您可能想改用 fs.appendFileSync()。这对于命令行工具来说没问题,但由于这是一个 Web 服务器,所以不要那样做。它会在 I/O 发生时锁定线程。

您可以使用非常适合控制流程的异步包,例如:

  console.log('Recieved the get Request');
  var i = 1;
  var count = 0;
  while (count < 10) {
    var url = 'http://www.imdb.com/title/tt' + i + '/';
    console.log(url);
    count = count + 1;
    i = i + 1;
    async.waterfall([
        function sendRequest (callback) {
            if (!error) {
                var $ = cheero.load(html);
                var json = {
                    title: '',
                    ratings: '',
                    released: ''
                }
            }
            $('.title_wrapper').filter(function() {
                var data = $(this);
                json.title = data.children().first().text().trim();
                json.released = data.children().last().children().last().text().trim();
            });
            $('.ratingValue').filter(function() {
                var data = $(this);
                json.ratings = parseFloat(data.text().trim());
            });
            callback(null, JSON.stringify(json, null, 4) + '\n');
        },
        function appendFile (json, callback) {
            fs.appendFile('message.txt', json, function(err) {
                if (err) { callback(err); }
                callback();
            });
        }
    ], function(err) {
        res.sendFile(__dirname + '/index.js');
    });