Async/Await 用iframe 跨域通信时回答onMessage 事件
Async/Await answer onMessage event in cross-domain communication with an iframe
我有一个 iframe,它正在与其父 window 通信以通过 postMessage method 设置和获取一些基本的 cookie。
首先,iframe 应用程序中的一个函数从父 window 请求 Cookie A。
function requestCommunication(topic, customerId) {
function cookieAvailable() {
return new Promise((resolve) => resolve(getCookieData('cookieName'));
});
}
console.log(cookieAvailable());
if(!!cookieAvailable()) {
//doStuff
}
}
cookieAvailable()
触发从 iframe 到 parent.window 的消息。反过来,window returns cookie 及其数据作为字符串。这是通过使用以下内容完成的:
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)
}
我不知道如何正确使用 promise 将其交给我的初始触发函数。我将不胜感激。
您的代码中存在明显的问题和反模式。 cookieAvailable
将 return 一个 Promise,所以你的支票 if(!!cookieAvailable()) {
将永远是真实的。在检查是否确实有可用的 cookie 之前,您需要等待该 Promise 解决。
但实际上,你的 cookieAvailable
函数 return 是一个无用的 Promise 包装器:如果 thisChatClient.cookie.getCookieData
做 return 一个 Promise 然后 return 它直接,不需要将其包装在 Promise 中。
如果它 return 是一个同步结果,那么你只能通过将它包装在一个 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);
现在所有这些都无助于对您的问题做出正确的回答:您的两个代码块之间的 link 根本不清楚。
Nothing 调用两个函数。
您的 getCookieData
将等待 MessageEvent,但不会让任何人知道它正在等待。
我不确定你是如何计划让你的 iframe 知道它应该将包含此信息的消息发送到你的 window,但这是你必须考虑的事情。
但在去那里之前我应该注意:虽然它可能很诱人,但在 Promises 中包装事件通常不是一个好主意。
事件和承诺是不同的东西,后者应该只解决一次,而前者可能会触发多次,而且来自不同的来源。
IMM 只有在您确定事件只会触发一次时才这样做。对于 MessageEvent,你还远远不了解它。
您的用户很可能在他们的浏览器上有一个扩展程序,它将使用 postMessage 作为一种通信方式。如果在所有 iframe 上都添加了此扩展,则您的代码已损坏。
相反,您应该检查 MessageChannel API,它会为您提供沟通方式,您可以确定您将是唯一使用的人。
我不认为这个答案是解释 API 如何工作的正确位置,但请看一下 ,它解释了非常基础的内容。
由于您一定会控制两端,因此您可以从那里设置一个基于 Promise 的系统。
在您的主页上,您将准备 MessageChannel 对象,并在侦听响应时将其发送到 iframe。当此响应到来时,您将能够解决您的承诺。
在您的 iframe 中,您将在 window 上添加一个侦听器以捕获 MessageChannelPort。发生这种情况时,您将向您的服务请求 cookie 并通过 MessageChannel 的端口将其发回。
即使在此交换期间您的主 window 上收到一条消息,您也可以确定它不会是您正在等待的那个。
// 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>
我有一个 iframe,它正在与其父 window 通信以通过 postMessage method 设置和获取一些基本的 cookie。
首先,iframe 应用程序中的一个函数从父 window 请求 Cookie A。
function requestCommunication(topic, customerId) {
function cookieAvailable() {
return new Promise((resolve) => resolve(getCookieData('cookieName'));
});
}
console.log(cookieAvailable());
if(!!cookieAvailable()) {
//doStuff
}
}
cookieAvailable()
触发从 iframe 到 parent.window 的消息。反过来,window returns cookie 及其数据作为字符串。这是通过使用以下内容完成的:
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)
}
我不知道如何正确使用 promise 将其交给我的初始触发函数。我将不胜感激。
您的代码中存在明显的问题和反模式。 cookieAvailable
将 return 一个 Promise,所以你的支票 if(!!cookieAvailable()) {
将永远是真实的。在检查是否确实有可用的 cookie 之前,您需要等待该 Promise 解决。
但实际上,你的 cookieAvailable
函数 return 是一个无用的 Promise 包装器:如果 thisChatClient.cookie.getCookieData
做 return 一个 Promise 然后 return 它直接,不需要将其包装在 Promise 中。
如果它 return 是一个同步结果,那么你只能通过将它包装在一个 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);
现在所有这些都无助于对您的问题做出正确的回答:您的两个代码块之间的 link 根本不清楚。
Nothing 调用两个函数。
您的 getCookieData
将等待 MessageEvent,但不会让任何人知道它正在等待。
我不确定你是如何计划让你的 iframe 知道它应该将包含此信息的消息发送到你的 window,但这是你必须考虑的事情。
但在去那里之前我应该注意:虽然它可能很诱人,但在 Promises 中包装事件通常不是一个好主意。
事件和承诺是不同的东西,后者应该只解决一次,而前者可能会触发多次,而且来自不同的来源。
IMM 只有在您确定事件只会触发一次时才这样做。对于 MessageEvent,你还远远不了解它。
您的用户很可能在他们的浏览器上有一个扩展程序,它将使用 postMessage 作为一种通信方式。如果在所有 iframe 上都添加了此扩展,则您的代码已损坏。
相反,您应该检查 MessageChannel API,它会为您提供沟通方式,您可以确定您将是唯一使用的人。
我不认为这个答案是解释 API 如何工作的正确位置,但请看一下
由于您一定会控制两端,因此您可以从那里设置一个基于 Promise 的系统。
在您的主页上,您将准备 MessageChannel 对象,并在侦听响应时将其发送到 iframe。当此响应到来时,您将能够解决您的承诺。
在您的 iframe 中,您将在 window 上添加一个侦听器以捕获 MessageChannelPort。发生这种情况时,您将向您的服务请求 cookie 并通过 MessageChannel 的端口将其发回。
即使在此交换期间您的主 window 上收到一条消息,您也可以确定它不会是您正在等待的那个。
// 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>