I have an iframe, which is communicating with its parent window to set and get some essential cookies via postMessage method.
At first a function in the iframe application requests Cookie A from the parent window.
function requestCommunication(topic, customerId) {
function cookieAvailable() {
return new Promise((resolve) => resolve(getCookieData('cookieName'));
});
}
console.log(cookieAvailable());
if(!!cookieAvailable()) {
//doStuff
}
}
cookieAvailable()
triggers the message from the iframe to the parent.window. In turn, the window returns the cookie with its data as string. This gets done by using the following:
async function getCookieData(cookieName) {
const {data} = await new Promise(resolve => {
window.onmessage = (event) => {
resolve(event);
}
});
var cookieContent = JSON.parse(data);
var cookieContentData = JSON.parse(cookieContent.data);
return cookieContentData; //this returns the cookie data (in almost all cases)
}
I don't get how to use the promise correctly to hand it over to my initial trigger function. I would appreciate any support.
There are obvious problems and anti-patterns in your code. cookieAvailable
will return a Promise, so your check if(!!cookieAvailable()) {
will always be truthy. You will want to wait for that Promise to resolve before checking if there is indeed a cookie available.
But actually, your cookieAvailable
function returns a Promise wrapper for nothing: If thisChatClient.cookie.getCookieData
does return a Promise then return it directly, no need to wrap it in a Promise.
And if it returns a synchronous result, then you will only loose by wrapping it in a Promise
async function requestCommunication(topic, customerId) {
function cookieAvailable() {
// this is already a Promise
return thisChatClient.cookie.getCookieData('sess_au');
}
const isCookieAvailable = await cookieAvailable();
if (!!isCookieAvailable) {
}
}
requestCommunication().catch(console.error);
Now all this can't help to make a proper answer to your question: The link between your two code blocks is not clear at all.
Nothing calls neither functions.
Your getCookieData
will be waiting for a MessageEvent, without letting anyone know that it is waiting for it.
I'm not sure how you did plan on letting your iframe know that it should send a message with this information to your window, but that's something you must consider.
But before going there I should note: as tempting as it could be, wrapping events in Promises is generally a bad idea.
Events and Promises are different things, the latter should resolve only once while the former may fire multiple times, and from different sources.
IMM it is only good to do so when you are sure the event will fire only once. With the MessageEvent, you are far from knowing it.
Your user may very well have an extension on their browser that will use postMessage as a means for communication. If this extension is added on all iframes, your code is broken.
Instead, you should check the MessageChannel API, which will offer you mean of communication that you can be sure you'll be the only ones using.
I don't think this answer is the right place to explain how this API works, but have a look at this overview which explains the very basics.
Since you'll be sure to be in control of both ends, from there you may set up a Promise based system.
From your main page, you'll prepare the MessageChannel object, and send it to the iframe while listening for a response. When this response will come, you'll be able to resolve your Promise.
From your iframe, you'll add a listener on the window to trap the MessageChannelPort. When this happens, you'll ask your service for the cookie and send it back through the MessageChannel's port.
Even if a message comes on your main's window during this exchange, you can be sure that it won"t be the one you are waiting for.
// Sets up a new MessageChannel
// so we can return a Promise
function getCookieData() {
return new Promise((resolve) => {
const channel = new MessageChannel();
// this will fire when iframe will answer
channel.port1.onmessage = e => resolve(e.data);
// let iframe know we're expecting an answer
// send it its own port
frame.contentWindow.postMessage('getCookie', '*', [channel.port2]);
});
}
frame.onload = async e => {
const frameHasCookie = await getCookieData();
console.log(frameHasCookie);
};
frame.src = generateFrameSRC();
function generateFrameSRC() {
// The content of your iframe
const cont = `
<html>
<head>
<script>
const originClean = "null";
onmessage = async e => {
// only if it's the origin we expected
// and if it does send a MessagePort
// and the message is "getCookie"
if(e.origin === originClean && e.ports && e.data === "getCookie") {
const data = await asyncData();
// respond to main window
e.ports[0].postMessage(data);
}
};
function asyncData() {
return new Promise(resolve =>
setTimeout(() => resolve("the data"), 1000)
);
}
<\/script>
</head>
<body>
hello
</body>
</html>`;
return 'data:text/html,' + encodeURIComponent(cont)
}
<iframe id="frame"></iframe>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With