1

MY issue is parse large xml file (with xml2js), and forEach element in cycle(product) , download image and save it to file. I wrote this code:

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

But after run I got this error :

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 
5
  • 1
    readFileSync returns a value and not a promise, you're returning from parseString which doesn't make sense since it takes a callback (vs returns a promise). Look into how to convert callback APIs to promises. Commented Jun 28, 2015 at 12:58
  • readFileSync does return the file contents, not a promise?! Commented Jun 28, 2015 at 12:59
  • Why are you importing async and q, but using neither? Commented Jun 28, 2015 at 12:59
  • Maybe you can help me with, how I can use promises with readFile async implementation Commented Jun 28, 2015 at 13:02
  • 1
    @MeetJoeBlack: see How do I convert an existing callback API to promises? Commented Jun 28, 2015 at 13:15

3 Answers 3

3

I think you're mistaking fs.readFileSync for fs.readFileAsync. The former is an in-built function of fs which returns the data directly. The latter is a function created by promisification by Bluebird which returns a promise.

Here's how differently they'd be used:

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

Notice the require('bluebird') and Promise.promisifyAll(fs) which are required to actually create fs.readFileSyncAsync which otherwise wouldn't have been available on fs

With that hopefully cleared, here's how I think you'd want to re-write your code:

Some changes I think you need are:

  1. You don't actually need the function readFile, you can just use fs.readFileAsync directly.

  2. Your parseString which comes from require('xml2js') would be better if you just promisified xml2js itself like fs and used xml2js.parseStringAsync

I've also gone ahead and taken the code from your previous question which presumably be more helpful in you understanding the whole picture:

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); })); } 
Sign up to request clarification or add additional context in comments.

1 Comment

thx for help. But when I run my code with yours help, I got all 360 messages with console.log('Processing file ' + product.sku); and only after that I saw file downloaded message. Why I didnt see one messages with 'Processing file... + product.sku' and '..file downloaded' and etc, So its seems to me my code still not working in order. And message console.log('All prdt have been processed successfully'); not displayed, the program freeze on test.com/uploads/catalog_item_image_main/EWS7928FP_big.png - downloaded
0

fs.readFileSync returns an end value (either string or a buffer). It SYNCHRONOUS. There is no promise involved in your code, and so you get the TypeError

Comments

0

readFileSync does not return a promise, the way to use it is

value = readFileSync(filename, options);

value will be either a string or buffer, depending on encoding option

see https://nodejs.org/api/fs.html#fs_fs_readfilesync_filename_options

1 Comment

So if I use fs.readFile instead , what I need to change im my code?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.