node js async function return Promise { <pending> } - javascript

i had try to test out an encryption stuff and im new to nodejs.
after several try and search over google, i unable to solve my problem.
please help.
case: calling async method to encrypt data, however it return me with a Promise { <pending> }
im using npm openpgp
objective: return the ciphertext so i could use it for other purpose
my code as below:
//execution.js
var tools = require('./tools');
console.log(tools.encrypt());
//tools.js
const openpgp = require('openpgp') // use as CommonJS, AMD, ES6 module or via window.openpgp
var fs = require('fs');
openpgp.initWorker({ path:'openpgp.worker.js' }) // set the relative web worker path
var pubkey = fs.readFileSync('public.key', 'utf8');
const passphrase = `super long and hard to guess secret` //what the privKey is encrypted with
module.exports = {
encrypt:async () =>{
const options = {
message: openpgp.message.fromText('Hello, World!'), // input as Message object
publicKeys: (await openpgp.key.readArmored(pubkey)).keys, // for encryption
}
const encrypted = await openpgp.encrypt(options);
const ciphertext = encrypted.data;
fs.writeFile('message.txt',ciphertext ,'utf8', function (err) {
if (err) throw err;
console.log('msg written!');
});
return ciphertext;
},
decrypt: async function(){
// your code here
}
};
please help

Async Await is simply syntactic sugar for promises an async function returns a promise.
You can't use await at the top level. What you can do is:
(async () => {
try {
console.log(await tools.encrypt());
} catch (e) {
console.log(e);
}
})();
// using promises
tools.encrypt().then(console.log).catch(console.log);

tools.encrypt().then(res => console.log(res))
this line from #mark meyer solve my problem.
i was trying to access the thing without have to declare the 'async' word and have access to the 'res' so i could use for other purpose
Thanks alot.

Related

Understanding promises async/await using parseCSV, what am I missing?

I feel like I a missing something fundamental here. I simply want to ensure "data" holds the parsed data from parseCSV before I continue to clean/edit it.
What am I missing? I fundamentally understand async / await but I suppose there is something I don't understand when it comes to callbacks and async / await.
const csv = require("csv");
const fs = require("fs");
(async function start() {
const file = importCSV("src/tg.csv");
const data = await parseCSV(file);
console.log(await parseCSV(file)); // why does this print a parser and not the parsed data?
})();
function importCSV(path) {
return fs.readFileSync(path, "utf8");
}
async function parseCSV(file) {
return await csv.parse(file, { columns: true }, async (err, data) => {
if (err) return err;
//console.log(data);
return data;
});
}
Because you are not returning the data. the csv.parse is not a promise so basically the data is being returned to the parent function of the anonymous callback function.
Just think of the implementation of a function who uses callback, how do you implement that?
const a = (cb) => {
const data = getdatafromsomewhere();
cb(data);
}
so if your function is not specifically returning to the parent function the returned data is not referenced from anywhere.
So the easiest way would be to promisify the csv.parse
const util = require('util');
const promiseParse = util. promisify(csv.parse);
function parseCSV(file) {
return promiseParse(file, { columns: true })
}

Sinon crypto stub for method within a callback

I'm trying to test a simple function that generates a random name using the nodejs crypto library. I'm using sinon to stub out a method call within the callback of pseudoRandomBytes but the stub doesn't seem to be called. Example:
getFileName.js
const crypto = require('crypto');
module.exports = (req, file, cb) => {
crypto.pseudoRandomBytes(32, (err, raw) => {
try{
cb(err, err ? undefined : crypto.createHash('MD5').update(raw).digest('hex'));
} catch(err) {
cb(err);
}
});
};
Test (running in mocha)
it('Crypto Error: createHash', function () {
const crypto = require('crypto');
const expectedError = new Error('stub error occurred');
let cryptoStub = sinon.stub(crypto, 'createHash').throws(expectedError);
let callback = sinon.spy();
getFileName(null, null, callback);
cryptoStub.restore();
sinon.assert.calledWith(callback, expectedError);
});
I would expect the above test to throw once createHash gets called. If I move the crypto.createHash call outside of the callback (before the pseudoRandomNumber call) it works just fine. I a bit of a newbie so my basic understanding of what sinon and nodejs are doing could be completely wrong. Any help would be much appreciated.
The reason why it seems like createHash() wasn't called was because you were making an assertion before the callback call was complete due to asynchronous function.
Promise with async/await will work. Another method which doesn't involve changing your module to use promise is to do your assertions within the callback.
it('Crypto Error: createHash', function (done) {
const crypto = require('crypto');
const expectedError = new Error('stub error occurred');
let cryptoStub = sinon.stub(crypto, 'createHash').throws(expectedError);
getFileName(null, null, function (err, hash) {
sinon.assert.match(err, expectedError);
cryptoStub.restore();
done();
});
});
This way, you can check that the callback is called with the expected error. One way to confirm this is you can change line 4 to .throws('some other error') and the test will fail.
The problem is that crypto.pseudoRandomBytes() is an async function, so the rest of your test code executes before your callback. That way, your stub is restored before your function is actually used it.
In order to make it properly work, you should update your getFileName.js so it returns a promise - that way you can await it
module.exports = (req, file, cb) => {
return new Promise((resolve, reject) => {
crypto.pseudoRandomBytes(32, (err, raw) => {
try{
cb(err, err ? undefined : crypto.createHash('MD5').update(raw).digest('hex'));
resolve();
} catch(err) {
reject(cb(err));
}
});
});
};
and then in your test
// added async
it('Crypto Error: createHash', async () => {
const crypto = require('crypto');
const expectedError = new Error('stub error occurred');
let cryptoStub = sinon.stub(crypto, 'createHash').throws(expectedError);
let callback = sinon.spy();
await getFileName(null, null, callback);
// once we are here, the callback has already been executed and the promise that getFileName resolved.
cryptoStub.restore();
sinon.assert.calledWith(callback, expectedError);
});

can await/async makes blocking to non-blocking process in javascript

I read this article from node
https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/
It says the code below is a process blocker:
const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
console.log(data);
// moreWork(); will run after console.log
what if I add await?
will the code above becomes non-blocking or it will stay in its true nature?
Example code:
const fs = require('fs');
const data = await fs.readFileSync('/file.md'); // no more blocking
console.log(data);
Thank you
No, the code can't run since await must use in async function.
And await should use for function that return promise.
the code means:
// await new Promise(...)
// console.log(...)
new Promise().then((...) => console.log(...))
If you should non-block function, you should use fs.readFile instead.
Blocking means that the whole application is blocked.
So, all SetInterval, Promise, Events or whatever async callback are paused until that sync function ends its execution.
It's the same of what you get when you use a for..loop.
NodeJS provides you some non-blocking file system methods with callbacks, just change your code like this.
const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
if (err) throw err;
console.log(data)
});
There is the only way.
await operator wait a promise, and wrapped in async function
you should code like this
const fs = require("fs");
function readFile(fileName) {
return new Promise((resolve, reject) => {
fs.readFile(fileName, (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
async function f1() {
try {
var x = await readFile("foo.json");
console.log(x);
} catch (e) {
console.log(e); // 30
}
}
f1();

Returning a value after writing to a file is complete

Hi I am writing a function in Node JS for which I have to return a filepath. My problem is in that function I am writing to a file and I want after writing to a file is finished then my return should work. Before looking into code, I know this can be duplicate and I have really did a research on this but I am not just being able to get there. I have tried using callback but the problem is I want to return a value which is already defined. So, before making any judgement calls for duplicate or lack of research, please read the code.
Also, tried to return value in fs.append callback but still did not solved.
My function:
const fs = require('fs');
const path = require('path');
module.exports.createDownloadFile = (request) => {
let filePath;
if (request) {
const userID = xyz;
filePath = path.join(__dirname, userID.concat('.txt'));
fs.open(filePath, 'w', (err) => {
if (err) throw new Error('FILE_NOT_PRESENT');
fs.appendFile(filePath, 'content to write');
});
}
return filePath;
};
I am getting the filePath where I am calling function, it's just at that time file is empty that is why I want to return after file is written completely.
Promises allow you to structure code and return values more like traditional synchronous code. util.promisify can help promisify regular node callback functions.
const fs = require('fs')
const path = require('path')
const fsAppendFileAsync = util.promisify(fs.appendFile)
const fsOpenAsync = util.promisify(fs.open)
module.exports.createDownloadFile = async (request) => {
if (!request) throw new Error('nope')
const userID = xyz
let filePath = path.join(__dirname, userID.concat('.txt'))
let fd = await fsOpenAsync(filePath, 'w')
await fsAppendFileAsync(fd, 'content to write')
return filePath
};
Note that async/await are ES2017 and require Node.js 7.6+ or Babel.
Opening a file with w creates or truncates the file and promises will reject on errors that are thrown so I've left the error handler out. You can use try {} catch (e) {} blocks to handle specific errors.
The Bluebird promise library is helpful too, especially Promise.promisifyAll which creates the promisified Async methods for you:
const Promise = require('bluebird')
const fs = Promise.promisifyAll(require('fs'))
fs.appendFileAsync('file', 'content to write')
use promises like this :
const fs = require('fs');
const path = require('path');
module.exports.createDownloadFile = (request) => {
return new Promise((resolve, reject) => {
let filePath;
if (request) {
const userID = xyz;
filePath = path.join(__dirname, userID.concat('.txt'));
fs.open(filePath, 'w', (err) => {
if (err) reject(err);
else
fs.appendFile(filePath, 'content to write', (err) => {
if (err)
reject(err)
else
resolve(filePath)
});
});
}
});
};
and call it like this :
createDownloadFile(requeset).then(filePath => {
console.log(filePath)
})
or use sync functions without Promises:
module.exports.createDownloadFile = (request) => {
let filePath;
if (request) {
const userID = xyz;
filePath = path.join(__dirname, userID.concat('.txt'));
fs.openSync(filePath,"w");
fs.appendFileSync(filePath, 'content to write');
}
return filePath;
};

Strava-V3 & Javascript es6 generators = not compatible?

I'm using node-strava-v3 with Node 5.7 to retrieve JSON collections from Strava's API. Pretty simple actually, no problem actually.
I just want to take the opportunity to try the ES6 Generators. So far so good I think I get the concept. But in the case of this Node-Strava-V3 API wrapper, the methods never return a value or a promise directly. Only Callbacks are allowed.
Which brings me to the question : how can I insert the ES6 Generators concept into play?
Take this : (this requires access_token you can request on the Strava portal)
var strava = require('strava-v3');
var mainActivity = {id: 504641206};
strava.activities.get(mainActivity, function (err, data){
if(err){ console.log("Strava GET issue: ", err);
/// consume the JSON data here...
};
//rest of the code
but can I use the generators to pause until this "strava.activities.get()" method ends? this method does not return any, no value, no promise.
Thanks for all your suggestions
FJ
You could do this with generators and a library like co, but now we have async functions (ES2017, and can be transpiled for outdated environments).
Tangentially related: Any API that provides callbacks can be promise-ified:
const strava = require('strava-v3');
const mainActivity = {id: 504641206};
new Promise((resolve, reject) => {
strava.activities.get(mainActivity, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
}).then(
result => {
//rest of the code
},
error => {
// handle error
}
);
In fact, that common pattern is codified in util.promisify:
const strava = require("strava-v3");
const promisify = require("util").promisify;
const stravaActivitiesGet = promisify(strava.activities.get);
const mainActivity = {id: 504641206};
stravaActivitiesGet(mainActivity).then(
result => {
//rest of the code
},
error => {
// handle error
}
);
There are multiple libraries that promise-ify a whole API at once (rather than per-function), such as node-promisify.
If we use util.promisify and an async function:
const strava = require("strava-v3");
const promisify = require("util").promisify;
const stravaActivitiesGet = promisify(strava.activities.get);
const mainActivity = {id: 504641206};
(async () => {
try {
const data = await stravaActivitiesGet(mainActivity);
//rest of the code
} catch (error) {
// handle error
}
})();
That mostly makes sense if you're doing other asynchronous things in the logic.

Categories

Resources