I have 3 functions which I need to run in order and one needs to finish before the other runs so I've done this:
var fs = require('fs');
async function create() {
fs.writeFile('newfile.txt', 'some text here', (err) => {
if (err) throw err;
console.log('File is created successfully.');
return ('File is created successfully.');
});
}
async function waitt() {
setTimeout(() => { return 'waited!' }, 10000);
}
async function read() {
fs.readFile('newfile.txt', {encoding: 'utf-8'}, (err,data) => {
if (!err) {
console.log('received data: ' + data);
return ('received data: ' + data);
} else {
console.log(err);
}
});
}
async function process() {
let [r1, r2, r3] = await Promise.all([create(), waitt(), read()]);
console.log(r1 + ' ' + r2 + ' ' + r3);
}
process();
So, process() runs create() which creates a file, then run waitt() which just pauses and finally read() shows the contents of the file.
The issue I'm having is that it's running in this order:
create()
read()
and then waitt()
instead of
create()
waitt()
read()
which is what I want.
How can I fix this?
This won't work:
async function waitt() {
setTimeout(() => { return 'waited!' }, 10000);
}
Because, you're return-ing from within the setTimeout callback, not the async-marked wait function.
To mix callback-style code and async/await you must first convert callback style code to use Promises, or use fs-extra which already provides fs functions returning promises.
Something like this:
function waitt() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('waited...')
}, 10000)
})
}
The same applies to the rest of your functions.
Also note that if a function explicitly returns a Promise, it doesn't need to be marked as async to be awaited, since await essentially works with Promises.
Now for the order:
Promise.all doesn't guarantee order, for that you might be able to get away with a simple for..of, or just call the functions yourself.
function wait() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('waited...')
resolve('foo')
}, 500)
})
}
// Assume this is your promisified read function.
function read() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('read...')
resolve('bar')
}, 500)
})
}
// Assume this is your promisified create function.
function create() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('created...')
resolve('baz')
}, 500)
})
}
;(async () => {
try {
await create()
await wait()
await read()
} catch (err) {
console.error(err)
}
})()
Your problem is that Promise.all does not guarantee the order of processing, just that all the promises in the list are processed.
Can you not just say:
await create();
await read();
await waitt();
Related
I have an application that it has nodejs as backend and some scripts in Python
The problem is to make the 'PythonShell' (function to access the scripts) as a async function. I do not know why but it is not working.
I'll put the code from my router.js file and inside of it I put three 'console.log('steps')' to check the sequences.
It should be Step01 > Step02 > Step03, but as it is not working, It always prints Step01 > Step03 > Step02
Everything is working fine, except for this async problem! For me it should work as it is.
How can I edit my functions to execute first the 'goToscript/PythonShell' and then execute 'res.json(responseScript)'?
Thanks
router.put("/uploads/script-03", async (req, res) => {
let options = {
scriptPath: "scripts",
args: JSON.stringify(req.body)
};
const goToScript = async () => {
await PythonShell.run("script-01.py", options, (err, res) => {
if (err) {
}
if (res) {
responseScript = JSON.parse(res)
console.log('Step 02')
}
});
}
console.log('Step 01')
goToScript()
console.log('Step 03')
res.json(responseScript)
});
module.exports = router
A couple things:
1. Your goToScript is not actually async/returning a Promise
From what I can tell, PythonShell doesn't support async, only callbacks, so you can rewrite your gotToScript like so:
const goToScript = () => {
return new Promise((resolve, reject) => {
PythonShell.run("script-01.py", options, (err, res) => {
if (err) {
reject(err)
}
if (res) {
responseScript = JSON.parse(res)
console.log('Step 02')
resolve(responseScript)
}
})
})
}
const scriptResult = await goToScript()
This code will work like a regular async function, where the promise will resolve to the parsed JSON, and reject with the error if it meets one.
2. You are not awaiting your call to goToScript
When you want to make an async call that finishes in sequence with everything else, you need to await it. Take these two examples:
In this first chunk of code, waitFn waits before 100ms before logging "Step 2!":
const waitFn = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('Step 2!')
resolve()
}, 100)
})
}
console.log('Step 1!')
waitFn()
console.log('Step 3!')
Because you do not await the result of the Promise, your code doesn't care that is has not finished, and will print:
Step 1!
Step 3!
Step 2!
Instead, however, if you await the result of the Promise returned in waitFn, it will execute in order:
const waitFn = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('Step 2!')
resolve()
}, 100)
})
}
console.log('Step 1!')
await waitFn() // Finishes before moving on
console.log('Step 3!')
You can read a bunch more about Promises and async/await here :)
To be able to await function - this function needs to return a promise. In the npm page of your lib there is a description, about what PythonShell.run returns. It does not return a promise. So it is asynchronous, but not awaitable, it is callback based.
All you need to do - to promisify this function. Additionaly - you need to await the call to goToScript();.
router.put("/uploads/script-03", async (req, res) => {
let options = {
scriptPath: "scripts",
args: JSON.stringify(req.body)
};
const goToScript = async () => {
return new Promise((resolve, reject) => {
PythonShell.run("script-01.py", options, (err, res) => {
console.log("Step 02");
if (err) return reject(err);
return resolve(JSON.parse(res));
});
});
};
console.log("Step 01");
const responseScript = await goToScript();
console.log("Step 03");
res.json(responseScript);
});
module.exports = router;
When using a simple callback such as in the example below:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
How can the function be changed to use async / await? Specifically, assuming 'someEvent' is guaranteed to be called once and only once, I'd like the function test to be an async function which does not return until the callback is executed such as:
async test() {
return await api.on( 'someEvent' );
}
async/await is not magic. An async function is a function that can unwrap Promises for you, so you'll need api.on() to return a Promise for that to work. Something like this:
function apiOn(event) {
return new Promise(resolve => {
api.on(event, response => resolve(response));
});
}
Then
async function test() {
return await apiOn( 'someEvent' ); // await is actually optional here
// you'd return a Promise either way.
}
But that's a lie too, because async functions also return Promises themselves, so you aren't going to actually get the value out of test(), but rather, a Promise for a value, which you can use like so:
async function whatever() {
// snip
const response = await test();
// use response here
// snip
}
It's annoying that there isn't a straightforward solution, and wrapping return new Promise(...) is fugly, but I have found an ok work-around using util.promisify (actually it also kinda does the same wrapping, just looks nicer).
function voidFunction(someArgs, callback) {
api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => {
callback(null, response_we_need);
});
}
The above function does not return anything, yet. We can make it return a Promise of the response passed in callback by doing:
const util = require('util');
const asyncFunction = util.promisify(voidFunction);
Now we can actually await the callback.
async function test() {
return await asyncFunction(args);
}
Some rules when using util.promisify
The callback must be the last argument of the function that is gonna be promisify
The supposed-callback must be in the form (err, res) => {...}
Funny thing is we do not need to ever specifically write what's the callback actually is.
async/await is magic. You can create a function asPromise to handle this kind of situations:
function asPromise(context, callbackFunction, ...args) {
return new Promise((resolve, reject) => {
args.push((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
if (context) {
callbackFunction.call(context, ...args);
} else {
callbackFunction(...args);
}
});
}
and then use it when you want:
async test() {
return await this.asPromise(this, api.on, 'someEvent');
}
the number of args is variable.
You can achieve this without callbacks , use promise async await instead of callbacks here how I would do this. And also here I have illustrated two methods to handle errors
clickMe = async (value) => {
// begin to wait till the message gets here;
let {message, error} = await getMessage(value);
// if error is not null
if(error)
return console.log('error occured ' + error);
return console.log('message ' + message);
}
getMessage = (value) => {
//returning a promise
return new Promise((resolve, reject) => {
setTimeout(() => {
// if passed value is 1 then it is a success
if(value == 1){
resolve({message: "**success**", error: null});
}else if (value == 2){
resolve({message: null, error: "**error**"});
}
}, 1000);
});
}
clickWithTryCatch = async (value) => {
try{
//since promise reject in getMessage2
let message = await getMessage2(value);
console.log('message is ' + message);
}catch(e){
//catching rejects from the promise
console.log('error captured ' + e);
}
}
getMessage2 = (value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(value == 1)
resolve('**success**');
else if(value == 2)
reject('**error**');
}, 1000);
});
}
<input type='button' value='click to trigger for a value' onclick='clickMe(1)' />
<br/>
<input type='button' value='click to trigger an error' onclick='clickMe(2)' />
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(1)'/>
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(2)'/>
const getprice = async () => {
return await new Promise((resolve, reject) => {
binance.prices('NEOUSDT', (error, ticker) => {
if (error) {
reject(error)
} else {
resolve(ticker);
}
});
})}
router.get('/binanceapi/price', async function (req, res, next) {
res.send(await binanceAPI.getprice());});
I was searching online on how we create the traditional way of doing async function in Javascript but it wasn't available. I have implemented a promise function in my program, however the software that I am using (tableu) to create all custom styling does not support ES5-ES8 and async functions, as this will throw an error, so I was wondering if this is possible.
function promise() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), 500);
})
}
async function result() {
await promise();
}
result().then(render => {
customStyle()
});
All of my code shown is working fine. I'm wondering how can I convert this to the old way of doing async functions. Is this possible or is it only available in ES8?
Callbacks are the non-Promise or async/await way of doing this, and are basically how those things work under the hood.
Here's a simple example by modifying your snippet:
function promise(callback) {
setTimeout(() => callback(), 500);
}
function result() {
promise(callback);
}
function callback() {
customStyle();
};
Instead of result being an async function that you can await elsewhere in your code, it could also take a callback argument, like promise, that you would pass it when it's invoked. The implementation of that callback function would be like the then of an actual Promise.
Now you can see why the Promise API and async/await were such nice improvements to the spec.
To use promises the tradicional way, you have to replace the await and use .then(()=> ...). I'll try to show a snippet here to help you to understood.
The code that you have shown does not need the async or await, it goes well like that
function promise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('resolved')
resolve()
}, 500);
})
}
promise().then(render => {
customStyle()
});
Here i'll show you a code that have a good use of it and then I'll convert it:
function callSomeService() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('service whas called')
resolve({ idOfSomething: 1 })
}, 2000);
})
}
function callAnotherServiceUsingTheDataOfThePreviousCall(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('service whas called with', data)
resolve(['potato 1', 'potato 2', 'potato 3'])
}, 2000);
})
}
async function result() {
const serviceResponse = await callSomeService();
const arrayOfPotatos = await callAnotherServiceUsingTheDataOfThePreviousCall(serviceResponse);
return arrayOfPotatos.map((potato, index) => `${index} - ${potato}`)
}
result().then(arrayOfPotatos => {
arrayOfPotatos.forEach(potato => console.log(potato))
});
Now I'll convert it to not use async or await, but still using promises.
function callSomeService() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('service whas called')
resolve({ idOfSomething: 1 })
}, 2000)
})
}
function callAnotherServiceUsingTheDataOfThePreviousCall(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('service whas called with', data)
resolve(['potato 1', 'potato 2', 'potato 3'])
}, 2000)
})
}
function result() {
return callSomeService().then(serviceResponse => {
return callAnotherServiceUsingTheDataOfThePreviousCall(
serviceResponse
).then(arrayOfPotatos => {
return arrayOfPotatos.map((potato, index) => `${index} - ${potato}`)
})
})
}
result().then(arrayOfPotatos => {
arrayOfPotatos.forEach(potato => console.log(potato))
})
Those two last codes does the same thing, but the second use async and await and the third does not. Async and await are just a syntax sugar to use promises.
I expect that will help you.
var images = ['image', 'image2', 'image3'];
async function proccess_images(images) {
for (const image of images) {
await postprocess(image)
}
console.log('done'); //this prints out before for loop is finished
}
async function postprocess(image) {
await process(function(data) {
console.log(data);
}, image)
};
function process(callback, image) {
3rdpartylibrary.process(image, (err, data) => {
if(err) {
console.error(err);
} else {
console.log('not done')
callback(data);
}
})
}
proccess_images(images)
I'm having trouble getting an async/await function working with my code that does some image processing using a 3rd party library. I'm trying to get each image to finish processing before moving onto the next image, but currently all three start processing immediately without waiting. It seems like the 3rd party library is starting its process which makes the async/await function think its done, but how do I make sure the next image isn't processed until AFTER 3rdpartylibrary.process has finished processing the data? I've also tried putting
await new Promise ((resolve, reject) =>
In front of the 3rdpartylibrary function which stops them all from processing at the same time, but it causes the for loop to exit after processing the first image correctly. Any ideas as to what I'm doing wrong?
Your problem appears to be that your first function isn't returning a promise. await requires a promise to work correctly. Something like this should work:
async function postprocess(image) {
var output = await process(image);
console.log(output);
};
function process(image) {
return new Promise((resolve, reject) => {
3rdpartylibrary.process(image, (err, data) => {
if(err) {
console.error(err);
reject(err);
} else {
console.log('not done')
resolve(data);
}
})
});
}
Change the process function definition to wrap a Promise:
function process(image) {
return new Promise((resolve,reject) => {
3rdpartylibrary.process(image, (err, data) => {
if (err) reject(err);
resolve(data);
})
})
}
The key point being to remove any callback references, since now it returns a Promise so you can await it.
You want to wrap the 3rdpartylibrary in a promise. What you want to do is convert the callback style to a promise by wrapping it. This is a good article to refer to. Try this:
var images = ['image1', 'image2', 'image3'];
// mock thirdPartyLibrary
const thirdPartyLibrary = {
process: (image, callback) => {
console.log(`processing image ${image}`);
setTimeout(() => {
const noError = undefined;
callback(noError, `finished procesing image ${image}`);
}, 1000);
}
}
async function proccess_images(images) {
console.log('start');
for (const image of images) {
console.log(`before processing image ${image}`);
await process(image);
console.log(`after processing image ${image}`);
}
console.log('done');
}
function process(image) {
// wrap thirdPartyLibrary in promise
return new Promise((resolve, reject) => {
thirdPartyLibrary.process(image, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
})
})
}
proccess_images(images)
I have the following async function:
async function readFile () {
let content = await new Promise((resolve, reject) => {
fs.readFile('./file.txt', function (err, content) {
if (err) {
return reject(err)
}
resolve(content)
})
})
console.log(content)
}
readFile()
This runs just fine. It outputs the file buffer to the console as expected. But now, if I try to instead return the value:
async function readFile () {
let content = await new Promise((resolve, reject) => {
fs.readFile('./file.txt', function (err, content) {
if (err) {
return reject(err)
}
resolve(content)
})
})
return content
}
console.log(readFile())
I now get:
Promise { <pending> }
Why is this? Why can you use a value inside that function but when you return it out of the function it's now a Promise?
How do you actually make use of this in a normal workflow? For example, lets say I wanted to check if a file exists, then read in the file, then update some database with the content, the synchronous pseudo code would look something like this:
if (fileExists(path)) {
buffer = readFile(path)
updateDatabase(buffer)
}
That workflow consists of 3 individual async operations. How would you do something like this with async/await? Is the key that you have to have your entire script wrapped in an async function?
async function doSomething () {
if (fileExists(path)) {
buffer = readFile(path)
updateDatabase(buffer)
}
}
(Keep in mind that is just pseudo-code but hopefully its gets my point across).
All async functions return a promise as was mentioned in the comments. You could therefore re-write your readFile function like this:
function readFile() {
return new Promise((resolve, reject) => {
fs.readFile('./file.txt', function (err, content) {
if (err) {
return reject(err)
}
resolve(content)
})
})
}
You would then consume the return value of readFile via await:
console.log(await readFile()) // will log your actual file contents.
The usual workflow with this paradigm is to break your async operations into separate functions that each return a promise, and then run them all inside a broader async function, much like you suggest, but with awaits and some error handling like so:
async function doSomething () {
try {
const fileCheck = await fileExists(path)
if (fileCheck) {
const buffer = await readFile(path)
await updateDatabase(buffer)
// Whatever else you want to do
}
} catch (err) {
// handle any rejected Promises here.
}
}
const serchContentXmlFile = async (path, content) => {
return new Promise((resolve, reject) => {
fs.readFile(path, function (err, data) {
if (err) {
return reject(err)
}
resolve(data.indexOf(content))
})
})
}
await serchContentXmlFile("category.xml",xmlUrl);