node.js承诺错误的底层函数

时间:2015-06-28 12:56:23

标签: javascript node.js promise

我的问题是解析大型xml文件(带有xml2js),以及循环(产品)中的forEach元素,下载图像并将其保存到文件中。 我写了这段代码:

var fs = require('fs');
var request = require('request');
var parseString = require('xml2js').parseString;
var baseUrl = 'http://shop.nag.ru/uploads/catalog_item_image_main/';
var async = require('async');
var processImg = require('./downloader');
var q = require('q');

var readFileSync  = function (){
    var xml = fs.readFileSync("./test.xml", "utf8");
    return xml;
};

readFileSync.then(function(xml) {
            parseString(xml, function (err, result) {
                if(err)return error;
                return result.product_list.product;
            })
    })
    .then(function(products){
        products.forEach(function(prdt) {

        });
    }).catch(function (err) {
        console.log(err);
    });

但是跑完后我得到了这个错误:

readFileSync.then(function(xml) {
             ^
TypeError: undefined is not a function
    at Object.<anonymous> (D:\WorkVrp\nodeImageParser\processing.js:19:14)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
    at startup (node.js:129:16)
    at node.js:814:3

3 个答案:

答案 0 :(得分:3)

我认为您将fs.readFileSync误认为fs.readFileAsync。前者是fs的内置函数,它直接返回数据。后者是由 promisification by Bluebird创建的函数,它返回一个promise。

在这里,他们的使用方式有多么不同:

<强> fs.readFileSync

var fs = require('fs');

try {
    var data = fs.readFileSync('./file.xml', 'utf8');
    // do something with data
} catch(err) {
    console.error(err);
}

<强> fs.readFileAsync

var fs = require('fs');
var Promise = require('bluebird');
Promise.promisifyAll(fs);

fs.readFileSyncAsync('./file.xml', 'utf8')
.then(function(data){
    //do something with data
})
.catch(function(err){
    console.error(err);
});

请注意实际创建require('bluebird')所需的Promise.promisifyAll(fs)fs.readFileSyncAsync,否则fs无法使用readFile

随着希望被清除,以下是我认为您想要重新编写代码的方式:

我认为你需要的一些改变是:

  1. 您实际上并不需要fs.readFileAsync功能,您可以直接使用parseString

  2. require('xml2js')来自xml2js的{​​{1}}会更好fs本身就像xml2js.parseStringAsync并使用var fs = require('fs'); var request = require('request'); var xml2js = require('xml2js'); var Promise = require('bluebird'); Promise.promisifyAll(fs); Promise.promisifyAll(request); Promise.promisifyAll(xml2js); var baseUrl = 'http://test.com/uploads/catalog_item_image_main/'; var processImg = require('./downloader'); var processImgAsync = Promise.promisify(processImg); fs.readFileAsync("./test.xml", "utf8") .then(xml2js.parseStringAsync) .then(parseProductsAsync) // defined below .then(processProductsAsync) .then(function(){ console.log('All prdt have been processed successfully'); }) .catch(console.error); function parseProductsAsync(xmljsonresult){ return xmljsonresult.product_list.product; } function processProductsAsync(products){ return Promise.all(products.map(function(product){ console.log('Processing file ' + product.sku); var filename = product.sku + ""; filename = filename.replace(/\//g, '_'); return processImgAsync(baseUrl + filename + '_big.', filename); })); }

  3. 我也继续使用你previous question中的代码,这可能对你理解整个图片更有帮助:

    {{1}}

答案 1 :(得分:0)

fs.readFileSync返回结束值(字符串或缓冲区)。它是同步的。您的代码中没有任何承诺,因此您获得了TypeError

答案 2 :(得分:0)

readFileSync不返回承诺,使用它的方式是

value = readFileSync(filename,options);

值可以是字符串或缓冲区,具体取决于编码选项

请参阅https://nodejs.org/api/fs.html#fs_fs_readfilesync_filename_options