在 UpdatePanel 中对 Flash 对象的外部接口调用进行排队 - 需要改进吗?
Flash(实际上是 Flex)对象是使用 embedCallAC_FL_RunContent.js 脚本的修改版本在更新面板内的 ASP.Net 页面上创建的,因此可以动态写入。它是使用此脚本重新创建的,并且每次部分回发到该面板。页面上还有其他更新面板。
对于某些回发(部分和完整),外部接口调用(例如 $get('FlashObj').ExternalInterfaceFunc('arg1', 0, true);
)在服务器端准备并添加到页面使用 ScriptManager.RegisterStartupScript。它们嵌入到函数中并填充到 Sys.Application 的加载事件中,例如 Sys.Application.add_load(funcContainingExternalInterfaceCalls)
。
问题在于,由于 Flash 对象的状态可能会随着每次部分回发而改变,因此当 JavaScript -> 回发时,Flash (Flex) 对象和/或外部接口可能尚未准备好,甚至尚未存在于 DOM 中。进行 Flash 外部接口调用。它会导致“对象不支持此属性或方法”异常。
我有一个工作策略,如果 Flash 准备就绪,则立即进行ExternalInterface 调用,否则将它们排队,直到 Flash 宣布其准备就绪。
//Called when the Flash object is initialized and can accept ExternalInterfaceCalls
var flashReady = false;
//Called by Flash when object is fully initialized
function setFlashReady() {
flashReady = true;
//Make any queued ExternalInterface calls, then dequeue
while (extIntQueue.length > 0)
(extIntQueue.shift())();
}
var extIntQueue = [];
function callExternalInterface(flashObjName, funcName, args) {
//reference to the wrapped ExternalInterface Call
var wrapped = extWrap(flashObjName, funcName, args);
//only procede with ExternalInterface call if the global flashReady variable has been set
if (flashReady) {
wrapped();
}
else {
//queue the function so when flashReady() is called next, the function is called and the aruments are passed.
extIntQueue.push(wrapped);
}
}
//bundle ExtInt call and hold variables in a closure
function extWrap(flashObjName, funcName, args) {
//put vars in closure
return function() {
var funcCall = '$get("' + flashObjName + '").' + funcName;
eval(funcCall).apply(this, args);
}
}
每当我更新包含 Flash (Flex) 对象的更新面板时,我都会将 flashReady 变量设置为 dirty。
ScriptManager.RegisterClientScriptBlock(parentContainer, parentContainer.GetType(), "flashReady", "flashReady = false;", true);
我很高兴它能正常工作,但感觉就像是黑客攻击。对于闭包等概念,我仍然处于学习曲线上,为什么“eval()”显然是邪恶的,所以我想知道我是否违反了一些最佳实践,或者是否应该改进此代码,如果是的话,如何改进?谢谢。
A Flash (actually Flex) object is created on an ASP.Net page within an Update Panel using a modified version of the embedCallAC_FL_RunContent.js script so it can be written in dynamically. It is re-created with this script with each partial postback to that panel. There are also other Update Panels on the page.
With some postbacks (partial and full), External Interface calls such as $get('FlashObj').ExternalInterfaceFunc('arg1', 0, true);
are prepared server-side and added to the page using ScriptManager.RegisterStartupScript. They're embedded in a function and stuffed into Sys.Application's load event, for example Sys.Application.add_load(funcContainingExternalInterfaceCalls)
.
The problem is that because the Flash object's state state may change with each partial postback, the Flash (Flex) object and/or External Interface may not be ready or even exist yet in the DOM when the JavaScript -> Flash External Interface call is made. It results in an "Object doesn't support this property or method" exception.
I have a working strategy to make the ExternalInterface calls immediately if Flash is ready or else queue them until such time that Flash announces its readiness.
//Called when the Flash object is initialized and can accept ExternalInterfaceCalls
var flashReady = false;
//Called by Flash when object is fully initialized
function setFlashReady() {
flashReady = true;
//Make any queued ExternalInterface calls, then dequeue
while (extIntQueue.length > 0)
(extIntQueue.shift())();
}
var extIntQueue = [];
function callExternalInterface(flashObjName, funcName, args) {
//reference to the wrapped ExternalInterface Call
var wrapped = extWrap(flashObjName, funcName, args);
//only procede with ExternalInterface call if the global flashReady variable has been set
if (flashReady) {
wrapped();
}
else {
//queue the function so when flashReady() is called next, the function is called and the aruments are passed.
extIntQueue.push(wrapped);
}
}
//bundle ExtInt call and hold variables in a closure
function extWrap(flashObjName, funcName, args) {
//put vars in closure
return function() {
var funcCall = '$get("' + flashObjName + '").' + funcName;
eval(funcCall).apply(this, args);
}
}
I set the flashReady var to dirty whenever I update the Update Panel that contains the Flash (Flex) object.
ScriptManager.RegisterClientScriptBlock(parentContainer, parentContainer.GetType(), "flashReady", "flashReady = false;", true);
I'm pleased that I got it to work, but it feels like a hack. I am still on the learning curve with respect to concepts like closures why "eval()" is apparently evil, so I'm wondering if I'm violating some best practice or if this code should be improved, if so how? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不幸的是,我不得不采取与您正在做的非常相似的解决方法,两者都检查以确保 Flash 已准备好接受调用,然后对命令进行排队。
快速连续调用多个ExternalInterface 调用(间隔小于约400 毫秒)可能会导致某些调用被忽略或丢弃,这是一个已知问题。
我感受到你的痛苦!
Unfortunately I've had to do workarounds very similar to what you're doing, both with checking to make sure Flash is ready to accept calls, and then queuing commands.
It's a known issue that calling multiple ExternalInterface calls in quick succession (closer than about 400 milliseconds apart) may result in some getting ignored or dropped.
I feel your pain!