我在cgi中有一个非常简单的js函数,用于12年以上的事情。
目的是通过自定义URL处理程序在客户端pc上启动程序。 (运行命令行工具从文档扫描程序执行TWAIN扫描,然后将pdf发回到同一服务器上的相同cgi。)
<script>
function tsu(e,v) {
t = window.open("tsu://;${HTTP_HOST};"+e,"_blank");
t.close();
window.location.replace("tsu?"+v);
}
</script>
[...]
<input type="button" value="Scan" onClick="tsu('$TSU_QS','$TSU_VIEW_QS')">
$ HTTP_HOST,$ TSU_QS和$ TSU_VIEW_QS是生成此输出的ksh脚本cgi中的shell变量。
最终的window.location.replace()不需要处于同步顺序。这将重新加载此代码出现的相同cgi(ksh脚本),并带有一个新的查询字符串,告诉它等待预期的新pdf出现在服务器文件系统上,或者在完成加载之前超时,以便重新绘制页面现在包括新扫描和上传文件的缩略图和链接。
只有在open()启动外部处理程序之前才需要阻塞close()。即使只需要启动它,也不知道它何时完成。这是在重新加载当前窗口期间处理的。
现在,自2016-10-21以来,当Chrome将函数的默认行为更改为异步时,这不再有效。 close()发生得太快,外部处理程序应用程序永远不会发生。
最初,我尝试改为:
function tsu(e,v) {
t = window.open("tsu://;${HTTP_HOST};"+e,"_blank");
if (navigator.userAgent.toLowerCase().indexOf('chrom')>-1) {
t.addEventListener('load',t.close());
} else t.close();
window.location.replace("tsu?"+v);
}
它在某些情况下起作用而在其他情况下起作用。它使Windows机器工作,但仍然无法在OSX机器上工作。
通过简单地注释掉关闭来调试/验证,然后运行外部应用程序,但是我有一个我不想要的空白选项卡。
(我已经知道通过名称检测铬和铬不是长期答案,因为最终所有浏览器都会有相同的行为,但目前的问题是,Edge具有addeventlistener功能,但它不起作用是的,所以我不能简单地通过该功能的存在。)
所以这有三个问题:
1) 我无法弄清楚如何使用这个已经在每个浏览器中工作超过12年的简单3行javascript,并将其转换为使用新的异步/等待事物。
2) 我也无法弄清楚如何检测甚至可以尝试使用“等待”(如果这甚至是我需要的),因为“typeof await”表示“未定义”即使在当前的Chrome上展示了新的“ async-by-default“问题。该功能似乎是新功能,因此尝试在旧浏览器上使用它是一个错误,但是,我发现有关async / await的所有页面都没有说明如何检测何时合法使用它以及何时使用它。
3) 也许有一种方法可以省去整个tsu()函数,只需要为tsu:// ...提供一个简单的链接或按钮,就像mailto:link一样。并检测是否有其他方式点击重新加载当前页面? 然后我甚至不关心async / await。
[UPDATE] 到目前为止,从答案中加入了一些内容:
仅仅是为了测试,我现在删除了window.location.replace,因此在错误的时间替换当前窗口没有任何问题。
没有浏览器测试或功能测试,每次都做同样的事情
在addeventlistener的参数中使用了函数(){...}
因此,使用下面的代码,新选项卡打开,外部处理程序应用程序运行,新窗口永远不会关闭。控制台显示“尝试addEventListener”,但从不显示“获取事件”。这适用于OSX上的Chrome和Safari。
所以在这个版本中,事件监听器无法正常工作。
function tsu(e,v) {
t = window.open("tsu:;${HTTP_HOST};"+e,"_blank");
console.log("trying addEventListener");
t.addEventListener('load',function() {
console.log("got event");
t.close();
});
//window.location.replace("tsu?"+v);
}
[更新2] 我仍然没有找到一种方法让这个功能在2016年末Chrome改变之前就一直运行起来,但是我找到了一种不同的方式来获得我需要的东西,而不使用这个功能或根本不需要它。回答如下。
答案 0 :(得分:0)
两件事:
如果您打开的URL位于不同的Origin上,您将无法向window.open
返回值添加事件侦听器,这看起来就是这种情况 - 我看到您已切换tsu://
和as://
。如果你想继续这种方法,两个页面都必须在同一个Origin上。
async / await是Promises之上的抽象。我不认为这是你问题的最佳解决方案,所以我不会实现它 - 但如果你想采用这种方法,你的负载监听器必须解决这个问题。
你最好的选择是一个简单的黑客 - 只需等待一秒钟即可关闭窗口。
var t = window.open("as://;${HTTP_HOST};"+e,"_blank");
setTimeout(function() {
t.close();
}, 1000);
答案 1 :(得分:0)
让我们看看你的尝试:
function tsu(e,v) {
t = window.open("tsu://;${HTTP_HOST};"+e,"_blank");
if (navigator.userAgent.toLowerCase().indexOf('chrom')>-1) {
t.addEventListener('load',t.close());
} else t.close();
window.location.replace("/cgi-bin/tsu?"+v);
}
第一个显而易见的事情是您没有订阅该活动,而是立即致电t.close()
。
其次,为什么要尝试检测浏览器是否为chrome?订阅事件监听器是正确的方法,它应该适用于每个浏览器。如果它不能在某些浏览器上运行,那就是您想要解决的浏览器,而不是其他浏览器。
所以你的功能可能就是:
function tsu(e,v) {
t = window.open("tsu://;${HTTP_HOST};"+e,"_blank");
t.addEventListener('load',function() {
t.close();
// you need location replace here else the page could be redirected before the popup gets closed
window.location.replace("/cgi-bin/tsu?"+v);
});
}
经过一番思考后,如果您可以在加载后将弹出窗口编程为自动关闭,那会更好。
答案 2 :(得分:0)
我自己已经回答了。好吧,我找到了一个不同的答案来完成我的最终任务,但它没有回答“我怎么能让这3行今天连续执行,就像他们这么多年来一直执行的那样2016?”。
我刚刚发现,如果我完全放弃javascript并只使用普通表单输入按钮,我会得到我真正想要的大部分行为。
tsu:url启动。 注册的外部处理程序应用程序在客户端上运行 浏览器中显示的当前页面不会更改。 没有新窗口或标签可以担心关闭。
<form action="tsu://;host;string"><input type="submit" value="Scan"></form>
没有tsu(),没有onClick。
问题就在于,如果我使用这种方法,那么每当按下该按钮时,如何重新加载当前页面(使用我之前在cgi中生成的不同查询字符串)?
我尝试添加onClick只是为了运行window.location.replace()而不是tsu(),就像这样,但它没有改变当前页面。外部应用程序已启动,因此action = ...工作,但当前页面没有重新加载,因此onClick没有(似乎)工作。
<form action="tsu://;host;string"><input type="submit" value="Scan" onClick="window.location.replace('/index.html')"></form>
替代:
<form action="tsu://;host;string"><button onClick="window.location.replace('/index.html')">Scan</button></form>
但是如果我用alert()替换window.location.replace(),我就会得到警告,并且在action =“...”之前首先发生警告。
奇怪,但两个动作都发生了DID,所以我只是尝试用setTimeout()替换alert()(在里面重新加载)并且瞧,最终让我回到了Chrome已经决定打破12之前的位置几年......好吧,但是说真的,我不能说够了......
所以,最后的结论,这是有效的。
action = ...首先触发外部处理程序应用程序。 然后一瞬间,当前浏览器页面重新加载到指定的新URL(实际上与新查询字符串实际上是相同的URL)。
<form action="tsu://;host;string"><button onClick="setTimeout(function(){window.location.replace('other_url.html');},200)">Scan</button></form>
为了完整起见,将这些虚拟值替换为问题顶部的原始发布代码到这种新形式:
<form action="tsu://;${HTTP_HOST};${TSU_QS}","><button onClick="setTimeout(function(){window.location.replace('tsu?${TSU_VIEW_QS}');},200)">Scan</button></form>
最后,我认为这是比我一直做的更好的方式来做我正在做的事情。不再打开,然后立即关闭一个新窗口。当用户开始使用它时,我会观察并看看我是否需要将200高达1000左右。
感谢大家的建议和信息。