I use dom-to-image.js for converting dom to png image. As dom-to-image.js uses promise, the code executes asynchronously. I want to execute .then function synchronously.
I have the following code:
domtoimage.toPng(document.getElementById("main")).then(function(dataUrl) {
console.log(dataUrl);
}).catch(function(error) {
console.error('oops, something went wrong!', error);
});
console.log("this console should be executed after console.log(dataUrl)")
I want to execute .then function first, before executing console.log("this console should be executed after console.log(dataUrl)").
Please tell me some way to achieve this.
There are of course legit reasons to force synchronous execution of a promise in js. The most obvious is when require'ing a file that needs to initialize using some asynchronous stuff, and optimization is not an overriding concern.
Seems like the package synchronized-promise seems like it ought to do the trick. In your case (warning - untested..):
const dti = () => docstoimage.toPng(document.getElementById("main"))
.then(dataUrl => console.log('url: ', dataUrl))
.catch(err => console.error('oops: ', err))
const sp = require('synchronized-promise')
const syncDti = sp(dti)
syncDti() // performs the 'synchronized version'
console.log("this console should be executed afterwards")
You didn't mention if it's done in browser or in NodeJs. For NodeJs that's possible by using execSync or spawnSync from child_process:
import { spawnSync } from "child_process";
function doSyncStuff(domObj){
const output = spawnSync(...);
console.log("this logs in server");
return output;
bit of a necro, but I'm the author of https://www.npmjs.com/package/synchronous-promise - which was around before this question was raised and does what you want (:
Async functions are a promise.
You have to use the promise syntax with them or use await (async-await syntax) on them in another async function.
An example of the regular promise syntax would be: myPromise.then(() => {})
For what you are looking for, you can use the promise syntax on them to wait for them as if they aren't a promise. Do take care though, as the code in myPromise.then(() => {}) is synchronous and can't use async-await features. I've wrapped things in a main function but you don't need to for extra code but you don't need to.
You can then run the main function through the promise method.
For e.g:
async function myFunction() {
// Do stuff
}
async function main() {
// Do stuff
await myFunction()
}
async function mySecondaryFunction() {
// Do stuff
}
function mySynchronousFunction() {
console.log("hello")
}
main().then(() => {
mySynchronousFunction()
mySecondaryFunction().then(() => {
console.log("idk")
}
})
See, we can use both types of functions!
Do know, though that this doesn't actually make promises synchronous.
It just acts like they're synchronous.
EDIT: Uhhh, I just realized you could put the console.log you want to execute after in both the try and catch functions.
For those stumbling upon this now:
If you're not concerned with IE support, you could use async and await to execute the promise as though it were synchronous. The await syntax will pause execution of the function until the promise resolves, letting you write the code as if there wasn't a promise. To catch an error, you wrap it in a try/catch block.
The only catch is that using the await syntax requires you to wrap it inside a function declared with async.
async function toPng() {
try {
let dataUrl = await domtoimage.toPng(document.getElementById("main"));
console.log(dataUrl);
}
catch (error ) {
console.error('oops, something went wrong!', error);
}
console.log("this console should be executed after console.log(dataUrl)")
}
Related
I would like to run this code with babel:
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
inside an async function without await the first line. is this OK?
how else can I run something that I don't care?
Can I just fire the non-promisified function del('key',null) without a callback?
Yes, you can do that, and it will run the two asynchronous functions in parallel. You've just created a promise and thrown it away.
However, this means that when the promise is rejected you won't notice. You'll just get an unhandledRejection eventually which will crash your process if not handled.
Is this OK? How can I run something that I don't care?
Probably it's not OK. If you truly wouldn't care, you hadn't run it in the first place. So you should be clear and explicit what you care about (and what not):
do you want to wait? (for side effects)
do you need the result?
do you want to catch exceptions?
If you only want to wait and don't care for the result value, you can easily throw away the result:
void (await someAsyncFunction()); // or omit the void keyword,
// doesn't make a difference in an expression statement
If you don't care about exceptions, you can ignore them using
… someAsyncFunction().catch(function ignore() {}) …
You can throw that away, await it, do anything with it.
If you want the result, you have to await it. If you care about exceptions, but don't really want to wait, you may want to execute it in parallel with the following functions:
var [_, res] = await Promise.all([
someAsyncFunction(), // result is ignored, exceptions aren't
someOtherAsyncFunction()
]);
return res;
inside an async function without await the first line. is this OK?
Yes, there are cases where you'd want to do this which are perfectly reasonable. Especially where you don't care about the result - one example is an analytics tracking operation that should not interfere with business critical code.
how else can I run something that I don't care?
In many ways, however simply calling the promise function works. Your del without a callback would probably work in this case but some functions don't guard against not passing callbacks, so you can pass an empty function instead (.del('key', () => {})).
You do want to however make sure that you know about it failing, even if you don't want to disrupt the operation of code - so please consider adding a process.on("unhandledRejection', event handler to explicitly ignore these particular exceptions or suppress them via:
redisClient.delAsync('key').catch(()=>{});
Or preferably, something like:
redisClient.delAsync('key').catch(logErr);
From all the research I've made so far, I think it's fine to do it, as long as you guarantee that the function you are not awaiting for guarantees a way to handle its own errors in case that happens. For example, a try-catch wrapping the whole function body, like you see in the following snippet for the asyncFunction.
It doesn't matter if the function throws synchronously or asynchronously. It guarantees the your mainFunction will complete no matter what. That's the key point here.
If you don't guarantee that, you have to risks:
If it throws synchronously, your main function will not complete.
If it throws asynchronously, you'll get an unhandled excepction
// THIS IS SOME API CALL YOU DON'T WANT TO WAIT FOR
const mockAPI = () => {
console.log("From mockAPI");
return new Promise((resolve,reject) => {
setTimeout(() => reject("LATE THROW: API ERROR"), 500);
});
};
// THIS IS THE SOME ASYNC FUNCTION YOU CALL BUT NOT AWAIT FOR
const asyncFunction = async (syncThrow) => {
try {
console.log("Async function START");
if (syncThrow) throw new Error("EARLY THROW");
await mockAPI();
console.log("Async function DONE");
}
catch(err) {
console.log("From async function catch");
console.log(err.message || err);
return;
}
};
// THIS IS YOUR MAIN FUNCTION
const mainFunction = async (syncThrow) => {
try {
console.clear();
console.log("Main function START");
asyncFunction(syncThrow);
console.log("Main function DONE <<< THAT'S THE IMPORTANT PART");
}
catch(err) {
console.log("THIS WILL NEVER HAPPEN");
console.log(err);
}
};
<div>
<button onClick="mainFunction(true)">Sync throw</button>
<button onClick="mainFunction(false)">Async throw</button>
</div>
Not in Node.js.
Node does not wait for ever-pending Promises. If other tasks are already completed and there is nothing left in the event loop, the Node process will be terminated even though there exists pending promise.
For the following script, if someOtherAsyncFunction() get resolved in 5 seconds, but redisClientAsync.delAsync('key') takes 10 seconds to execute, the Node process will be terminated after 5 seconds in theory, before the first line is resolved.
async function doSomething() {
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
}
await doSomething();
I am reading MDN on how async code works with javascript. They propose this example:
async function myFetch() {
let response = await fetch('coffee.jpg');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
let myBlob = await response.blob();
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
}
myFetch()
.catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message);
});
Function myFetch() is defined and then it's called in a Promise-way style. How exactly is the function executed? It's an async function, so I assume that it's given to some thread to execute without interfering with the single thread that runs Javascript code?
Also in the docs they said await is stoping the code on that line until completion? So the function can't be executed by the main application thread because then it's not async code anymore?
So those are my issues and I wanna be sure I understand this mechanism before I start writing actual code. Thank you!
using async/await is pretty similar to using promises, async function returns a Promise for you, that promise can have one of three statuses (Pending, Fulfilled, Rejected)
By default, the returned Promise is Fulfilled (Resolved)
similar to:
Promise.resolve().then(_ => { //... })
using await, the Promise will be pending on the code that you are awaiting for
new Promise((resolve, reject) => {
// ... some tasks here
resolve(resolvedData);
})
.then(_ => { //... })
when an error is thrown, automatically or manually, the Promise will be rejected
new Promise((resolve, reject) => {
reject(); // Reject manually
})
.then(_ => { })
.catch(e => { //... })
By default, all JavaScript code is executing within the main thread, which is the only thread that JavaScript has
Look at the following example:
async function c() {
const t = await Array.from(Array(100000000).keys())
}
c().then(t => console.log('I am waiting for the Promise to be fulfilled!'))
console.log('Hey, I don\'t need to wait');
You will get the expected output:
"Hey, I don't need to wait"
"I am waiting for the Promise to be fulfilled!"
but both logs are waiting for filling this 100000000 array, so the main thread now is busy and blocked to complete this task first, JavaScript itself can't help with this case,
Another Example:
async function c() {
const t = await fetch('https://jsonplaceholder.typicode.com/photos')
}
c().then(_ => console.log('I am waiting for the Promise to be fulfilled!'))
console.log('Hey, I don\'t need to wait');
Here you'll get the same result, but Hey, I don't need to wait will be logged immediately, and only I am waiting for the Promise to be fulfilled! will be waiting,
Why? here we need to refer to few important things to read more about (Event Loop, Call Stack, Micro & Macro tasks )
In simple words, the promise behaves the same, it's pending on something, and the first console log in the code is awaiting the promise to be fulfilled,
the difference is that the task that we are waiting for to have a fulfilled promise now is not thread-blocking, it is not controlled by JavaScript itself
the fetching task is managed by an external API that is observed by the Event loop, in this case, the call stack will not be busy, and the main JavaScript thread can continue working, the code that will resolve the promise is added to a queue and will be pushed to the call stack by the Event loop when the fetching task is done by the external API
Function myFetch() is defined and then it's called in a Promise-way style.
It's called like any other function. All async functions wrap the return value in a Promise, thus there are then, catch and finally methods available.
How exactly is the function executed?
Using () like any other function.
It's an async function, so I assume that it's given to some thread to execute without interfering with the single thread that runs Javascript code?
There is no need to have it run on some other thread. As you say, JavaScript execution happens in a single thread.
Also in the docs they said await is stoping the code on that line until completion?
Yes, in that async function.
So the function can't be executed by the main application thread because then it's not async code anymore?
There doesn't have to be any threading involved. It is only the fetch and blob operations that are performed asynchronously. While those operations are being awaited, the event loop and the execution of code outside the async function will continue. If you have code below the call to myFetch then that will be executed while the fetch is being awaited, unless you await the call to myFetch itself.
async and await are syntactic sugar on top of Promises, so effectively your code is doing the following:
fetch('coffee.jpg').then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
response.blob().then(myBlob => {
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
});
}).catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message);
});
What if we do not wait for an asynchronous javascript function?
As far as I know some languages like C # should not run an asynchronous function unmanaged!
I wanted to know if this is also true for the JavaScript language?
var asynchronousFunction = async function() {
//...
}
function main() {
var result = true;
//...
asynchronousFunction(); // The result of this function has no effect on our output (result)
//...
return result;
}
It's run just the same. (In fact, you never await a function, you await for the the Promise it returns.)
The asynchronous function is run synchronously until the first await or return within it, at which point a Promise is returned to the caller and the rest of the function is arranged to run later.
It's up to the caller to do something (or nothing) to the Promise. After all, you might wish to store the promise in an array and await for the lot of them (Promise.all) or do something more esoteric about it, so JavaScript itself doesn't care.
Some smart enough IDEs and linters are able to raise a warning about unhandled promises, though, especially if you have enough type information to do so (e.g. by using TypeScript).
It's true for javascript as well.
You don't want to just create a promise and leave it totally hanging, if there are errors then they become unhandled errors and if it exits unexpectedly then you have no way of knowing that.
What I recommend is using the Promise.race at the top level and then it will run all of your async functions in parallel but will exit if any one of them exits unexpectedly.
async function worker() {
while (true) {
// do background work in a loop
}
}
async function server() {
await init()
await listen()
}
function main() {
const p0 = worker()
const p1 = server()
try {
await Promise.race([p0, p1])
console.log('done')
return true
} catch (err) {
console.log('The server had an error unexpectedly', err)
return false
}
}
If you expect the promises to eventually exit gracefully then use Promise.all instead, which will wait until all promises exit successfully before resolving.
I would like to run this code with babel:
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
inside an async function without await the first line. is this OK?
how else can I run something that I don't care?
Can I just fire the non-promisified function del('key',null) without a callback?
Yes, you can do that, and it will run the two asynchronous functions in parallel. You've just created a promise and thrown it away.
However, this means that when the promise is rejected you won't notice. You'll just get an unhandledRejection eventually which will crash your process if not handled.
Is this OK? How can I run something that I don't care?
Probably it's not OK. If you truly wouldn't care, you hadn't run it in the first place. So you should be clear and explicit what you care about (and what not):
do you want to wait? (for side effects)
do you need the result?
do you want to catch exceptions?
If you only want to wait and don't care for the result value, you can easily throw away the result:
void (await someAsyncFunction()); // or omit the void keyword,
// doesn't make a difference in an expression statement
If you don't care about exceptions, you can ignore them using
… someAsyncFunction().catch(function ignore() {}) …
You can throw that away, await it, do anything with it.
If you want the result, you have to await it. If you care about exceptions, but don't really want to wait, you may want to execute it in parallel with the following functions:
var [_, res] = await Promise.all([
someAsyncFunction(), // result is ignored, exceptions aren't
someOtherAsyncFunction()
]);
return res;
inside an async function without await the first line. is this OK?
Yes, there are cases where you'd want to do this which are perfectly reasonable. Especially where you don't care about the result - one example is an analytics tracking operation that should not interfere with business critical code.
how else can I run something that I don't care?
In many ways, however simply calling the promise function works. Your del without a callback would probably work in this case but some functions don't guard against not passing callbacks, so you can pass an empty function instead (.del('key', () => {})).
You do want to however make sure that you know about it failing, even if you don't want to disrupt the operation of code - so please consider adding a process.on("unhandledRejection', event handler to explicitly ignore these particular exceptions or suppress them via:
redisClient.delAsync('key').catch(()=>{});
Or preferably, something like:
redisClient.delAsync('key').catch(logErr);
From all the research I've made so far, I think it's fine to do it, as long as you guarantee that the function you are not awaiting for guarantees a way to handle its own errors in case that happens. For example, a try-catch wrapping the whole function body, like you see in the following snippet for the asyncFunction.
It doesn't matter if the function throws synchronously or asynchronously. It guarantees the your mainFunction will complete no matter what. That's the key point here.
If you don't guarantee that, you have to risks:
If it throws synchronously, your main function will not complete.
If it throws asynchronously, you'll get an unhandled excepction
// THIS IS SOME API CALL YOU DON'T WANT TO WAIT FOR
const mockAPI = () => {
console.log("From mockAPI");
return new Promise((resolve,reject) => {
setTimeout(() => reject("LATE THROW: API ERROR"), 500);
});
};
// THIS IS THE SOME ASYNC FUNCTION YOU CALL BUT NOT AWAIT FOR
const asyncFunction = async (syncThrow) => {
try {
console.log("Async function START");
if (syncThrow) throw new Error("EARLY THROW");
await mockAPI();
console.log("Async function DONE");
}
catch(err) {
console.log("From async function catch");
console.log(err.message || err);
return;
}
};
// THIS IS YOUR MAIN FUNCTION
const mainFunction = async (syncThrow) => {
try {
console.clear();
console.log("Main function START");
asyncFunction(syncThrow);
console.log("Main function DONE <<< THAT'S THE IMPORTANT PART");
}
catch(err) {
console.log("THIS WILL NEVER HAPPEN");
console.log(err);
}
};
<div>
<button onClick="mainFunction(true)">Sync throw</button>
<button onClick="mainFunction(false)">Async throw</button>
</div>
Not in Node.js.
Node does not wait for ever-pending Promises. If other tasks are already completed and there is nothing left in the event loop, the Node process will be terminated even though there exists pending promise.
For the following script, if someOtherAsyncFunction() get resolved in 5 seconds, but redisClientAsync.delAsync('key') takes 10 seconds to execute, the Node process will be terminated after 5 seconds in theory, before the first line is resolved.
async function doSomething() {
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
}
await doSomething();
Assume the scenario where you have to call an asynchronous function, but you are not really interested about success/failure situation of that function. In that case what are the pros and cons in following two patterns stated below with respect to call stack, callback queue and event loop
Pattern-1
async setSomething() {
try {
set(); // another async function
} catch (err) {
// log the error here
}
return true;
}
Pattern-2
async setSomething() {
try {
await set(); // another async function
} catch (err) {
// log the error here
}
return true;
}
Pattern 1 does not catch any errors that may occur during asynchronous operations in the set function - any errors will result in an unhandled Promise rejection, which should be avoided. Pattern 1 will only catch errors that occur during set's synchronous operations (such as, when setting up a fetch request), which are not likely to occur in most situations.
Example:
// open your browser's console to see the uncaught rejection
const set = () => new Promise((_, reject) => setTimeout(reject, 500));
async function setSomething() {
try {
set(); // another async function
} catch (err) {
console.log('err');
}
return true;
}
setSomething();
So, pattern 2 is likely preferable. If you don't care about the result of the asynchronous call, then don't await or call .then when you call setSomething().
Or, for something this simple, you might consider using Promise methods only, no async function needed:
const setSomething = () => set()
.catch((err) => {
// log the error here
});
This answer is a rather unconventional advice to the question than an actual answer to the examples posted by OP.
not really interested about success/failure situation of that function
If the above statement is the case, then it means, the return is not dependent on the result of the async invocation.
When you're not bothered about the return of the async invocation, it's better off to not use async/await or any type of promise at all. You could just invoke the function like any other function and process with the rest of the code.