Reputation: 1451
I need some help with my code. I'm new at Node.js and have a lot of trouble with it.
What I'm trying to do:
Fetch a .txt with Amazon products (ASINs) ;
Fetch all products using the amazon-product-api package;
Save each product in a .json file.
My code is not working. I think I messed up with this asynchronous-synchronous stuff - help me!
var amazon = require('amazon-product-api');
var fs = require('fs');
var client = amazon.createClient({
awsId: "XXX",
awsSecret: "XXX",
awsTag: "888"
});
var array = fs.readFileSync('./test.txt').toString().split('\n');
for (var i = 1; i < array.length; i++) {
var ASIN = array[i];
client.itemLookup({
domain: 'webservices.amazon.de',
responseGroup: 'Large',
idType: 'ASIN',
itemId: ASIN
})
.then(function(results) {
fs.writeFile(ASIN + '.json', JSON.stringify(results), function(err) {
if (err) {
console.log(err);
} else {
console.log("JSON saved");
}
})
return results;
}).catch(function(err) {
console.log(err);
});
};
Upvotes: 135
Views: 205845
Reputation: 671
import
, using promises(I've also refactored the code a bit to avoid nested try..catch
blocks, YMMV.
import * as fs from 'node:fs/promises';
async function doFile(filepath) { // choose a better name than `doFile` for your use case!!
try {
const fileData = await fs.readFile(filepath, {encoding: 'utf8'});
var array = fileData.toString().split('\n');
for (var i = 1; i < array.length; i++) {
var ASIN = array[i];
let results = await doClientStuff(args); // e.g. client.itemLookup
await saveResults(ASIN, results);
};
} catch (error) {
console.error(error?.message ?? error?.toString()); // or however you extract your error msg
}
}
async function saveResults(ASIN, results) {
try {
await fs.writeFile(ASIN + '.json', JSON.stringify(results));
console.log("JSON saved");
} catch (error) {
console.error(error?.message ?? error?.toString()); // or however you extract your error msg
}
}
await doFile('./test.txt');
This uses the OP's desire to us a fs
default import. I personally would change it to import only your individual functions and remove the fs.
references to enable esm tree-shaking:
import { readFile, writeFile } from 'node:fs/promises';
const fileData = await readFile(filepath, {encoding: 'utf8'}); // fs. removed
await writeFile(ASIN + '.json', JSON.stringify(results)); // fs. removed
readFile
docs:If no encoding is specified (using options.encoding), the data is returned as a object. Otherwise, the data will be a string.
Refer to Node documentation for additional info, including alternative usage with sync/callbacks. Be sure to select your correct version in the docs for your Node environment.
Upvotes: 6
Reputation: 323
Use require('fs/promises')
var fs = require('fs/promises'); // Since 11.14.0
var path = require('path'); // to help us to join better the paths
var content = JSON.stringify(["this is your content"]); // Must be a string to be written.
fs
.writeFile(path.join(__dirname, 'test.json'), content, { encoding: 'utf8' })
.then(() => {
console.log('Write is done!');
});
Example using async/await
var fs = require('fs/promises'); // Since 11.14.0
var path = require('path'); // to help us to join better the paths
var content = JSON.stringify(["this is your content"]); // Must be a string to be written.
(async function autorun(){
await fs.writeFile(path.join(__dirname, 'test.json'), content, { encoding: 'utf8' })
console.log('Write is done!');
})() // This is called a IIFE: Immediately invoked function expression
Upvotes: 3
Reputation: 1
Use fs.writeFileSync
inside the try/catch block as below.
var fs = require('fs');
try {
const file = fs.writeFileSync(ASIN + '.json', JSON.stringify(results))
console.log("JSON saved");
return results;
} catch (error) {
console.log(err);
}
Upvotes: -3
Reputation: 670
What worked for me was fs.promises.
Example One:
const fs = require("fs")
fs.promises
.writeFile(__dirname + '/test.json', "data", { encoding: 'utf8' })
.then(() => {
// Do whatever you want to do.
console.log('Done');
});
Example Two. Using Async-Await:
const fs = require("fs")
async function writeToFile() {
await fs.promises.writeFile(__dirname + '/test-22.json', "data", {
encoding: 'utf8'
});
console.log("done")
}
writeToFile()
Upvotes: 15
Reputation: 60527
If you want to import the promise based version of fs
as an ES module you can do:
import { promises as fs } from 'fs'
await fs.writeFile(...)
As soon as node v14 is released (see this PR), you can also use
import { writeFile } from 'fs/promises'
Upvotes: 18
Reputation: 2863
Because fs.writefile
is a traditional asynchronous callback - you need to follow the promise spec and return a new promise wrapping it with a resolve and rejection handler like so:
return new Promise(function(resolve, reject) {
fs.writeFile("<filename.type>", data, '<file-encoding>', function(err) {
if (err) reject(err);
else resolve(data);
});
});
So in your code you would use it like so right after your call to .then()
:
.then(function(results) {
return new Promise(function(resolve, reject) {
fs.writeFile(ASIN + '.json', JSON.stringify(results), function(err) {
if (err) reject(err);
else resolve(data);
});
});
}).then(function(results) {
console.log("results here: " + results)
}).catch(function(err) {
console.log("error here: " + err);
});
Upvotes: 65
Reputation:
...the correct answer is to use async/await with the native fs
promises module included in node. Upgrade to Node.js 10 or 11 (already supported by major cloud providers) and do this:
const fs = require('fs').promises;
// This must run inside a function marked `async`:
const file = await fs.readFile('filename.txt', 'utf8');
await fs.writeFile('filename.txt', 'test');
Do not use third-party packages and do not write your own wrappers, that's not necessary anymore.
Before Node 11.14.0
, you would still get a warning that this feature is experimental, but it works just fine and it's the way to go in the future. Since 11.14.0
, the feature is no longer experimental and is production-ready.
import
instead of require
?It works, too - but only in Node.js versions where this feature is not marked as experimental.
import { promises as fs } from 'fs';
(async () => {
await fs.writeFile('./test.txt', 'test', 'utf8');
})();
Upvotes: 288
Reputation: 14926
Finally, the latest node.js release v10.3.0 has natively supported fs promises.
const fsPromises = require('fs').promises; // or require('fs/promises') in v10.0.0
fsPromises.writeFile(ASIN + '.json', JSON.stringify(results))
.then(() => {
console.log('JSON saved');
})
.catch(er => {
console.log(er);
});
You can check the official documentation for more details. https://nodejs.org/api/fs.html#fs_fs_promises_api
Upvotes: 25
Reputation: 10200
const util = require('util')
const fs = require('fs');
const fs_writeFile = util.promisify(fs.writeFile)
fs_writeFile('message.txt', 'Hello Node.js')
.catch((error) => {
console.log(error)
});
Upvotes: 2
Reputation: 2286
say
const util = require('util')
const fs_writeFile = util.promisify(fs.writeFile)
https://nodejs.org/api/util.html#util_util_promisify_original
this is less prone to bugs than the top-voted answer
Upvotes: 63
Reputation: 7289
Update Sept 2017: fs-promise
has been deprecated in favour of fs-extra
.
I haven't used it, but you could look into fs-promise. It's a node module that:
Proxies all async fs methods exposing them as Promises/A+ compatible promises (when, Q, etc). Passes all sync methods through as values.
Upvotes: 4
Reputation: 2873
For easy to use asynchronous convert all callback to promise use some library like "bluebird" .
.then(function(results) {
fs.writeFile(ASIN + '.json', JSON.stringify(results), function(err) {
if (err) {
console.log(err);
} else {
console.log("JSON saved");
return results;
}
})
}).catch(function(err) {
console.log(err);
});
Try solution with promise (bluebird)
var amazon = require('amazon-product-api');
var fs = require('fs');
var Promise = require('bluebird');
var client = amazon.createClient({
awsId: "XXX",
awsSecret: "XXX",
awsTag: "888"
});
var array = fs.readFileSync('./test.txt').toString().split('\n');
Promise.map(array, function (ASIN) {
client.itemLookup({
domain: 'webservices.amazon.de',
responseGroup: 'Large',
idType: 'ASIN',
itemId: ASIN
}).then(function(results) {
fs.writeFile(ASIN + '.json', JSON.stringify(results), function(err) {
if (err) {
console.log(err);
} else {
console.log("JSON saved");
return results;
}
})
}).catch(function(err) {
console.log(err);
});
});
Upvotes: -2