javascript - 一些书签不在 iOS 上执行:如何调试?
问题描述
更新 2:显然,只要 2410 个字符的小书签毕竟可以完全正常工作,我使用表单的脚本对其进行了测试javascript: var a=0; a++; a++; ... window.alert(a);
。在 9424 个字符处,小书签的 Chrome 同步失败,但通过从电子邮件复制/粘贴书签,我仍然能够执行它。目前尚不清楚,为什么某些脚本在作为脚本标记时工作(参见更新 1),但在javscript:
直接从 URL 执行时会失败。
更新 1:<script/>
通过生成指向托管在 Dropbox 上的脚本的标签,看起来相同的小书签可以工作。这只是作为解释,iOS 上的浏览器引擎对javascript:
URL 的硬编码限制少于 1024 个字符。
原帖
我试图弄清楚为什么一些书签在 iOS 上什么都不做——甚至没有触发错误——无法访问 Mac OS 设备。
作为参考,请考虑以下两个书签(下面的格式化源):
// DebugSimple.js
javascript:/* DebugSimple.js - 10:02:50 2019-12-23 */(function(){ document.body.innerHTML='';document.body.style.all='initial';function putString(string){document.body.innerText+=string;}const oldConsoleLog=console.log;console.log=function(...args){putString('(log) '+args.map(e=>e.toString()).join(' '));return oldConsoleLog(...args);};window.addEventListener('error',event=>{var msg='\n(err) ';msg+=!event ?'!!event = '+event :!event.error ?'!!event.error = '+event.error :!event.error.stack ?'!!event.error.stack = '+event.error.stack : event.error.stack;if(event&&event.error)for(const key in event.error){msg+='\nevent.error.'+key+'='+event.error[key];}putString(msg);});console.log("Log test.");setTimeout(backtraceTest,10);function backtraceTest(){backtraceTest2();}function backtraceTest2(){noSuchFunctionShouldExist();}})();undefined;
// DebugOverlay.js
javascript:/* DebugOverlay.js - 10:07:25 2019-12-23 */(function(){ const highestZIndex=Math.max(...Array.from(document.getElementsByTagName('*')).map(e=>window.getComputedStyle(e).zIndex).map(parseInt).filter(e=>!isNaN(e)));console.log(highestZIndex);function append(parent,html,callback=undefined){var e=document.createElement('DIV');parent.appendChild(e);e.outerHTML=html;e=parent.lastElementChild;if(callback)callback(e);return e;}const ifr=document.createElement('IFRAME');document.body.prepend(ifr);ifr.id='debugOverlay.js';ifr.style.all='initial';ifr.style.zIndex=highestZIndex+1;ifr.style.position='fixed';ifr.style.left='5%';ifr.style.right='5%';ifr.style.width='90%';ifr.style.height='90%';ifr.style.opacity='90%';ifr.style.backgroundColor='#ddd';ifr.style.border='1pt solid #888';ifr.contentDocument;ifr.contentDocument.open();ifr.contentDocument.close();const header=append(ifr.contentDocument.body,"<DIV id='header'/>",e=>{e.style.position='static';});const closeButton=append(header,"<A href='#' id='closeButton'>[CLOSE]</A>",e=>{e.addEventListener('click',()=>ifr.parentElement.removeChild(ifr));});const clearButton=append(header,"<A href='#' id='clearButton'>[CLEAR]</A>",e=>{e.addEventListener('click',()=>{output.innerHTML='';});});const output=append(ifr.contentDocument.body,"<DIV id='outputPane'/>",e=>{e.style.fontFamily='Sans';});append(ifr.contentDocument.body,"<DIV id='overScroll' style='height:30vh'/>");var fontSizeScale=0.8;function setOutputFontSize(scale){output.style.fontSize=(fontSizeScale*100)+'%';}setOutputFontSize(fontSizeScale);const fontSizePlus=append(header,"<A href='#' id='fontSizePlus'>[LGR]</A>",e=>{e.addEventListener('click',()=>{setOutputFontSize(fontSizeScale*=1.2);});});const fontSizeMinus=append(header,"<A href='#' id='fontSizePlus'>[SML]</A>",e=>{e.addEventListener('click',()=>{setOutputFontSize(fontSizeScale/=1.2);});});const toggleLog=append(header,"<A href='#' id='toggleLog'>[log(on)]</a>",e=>{var logVisibility=true;e.addEventListener('click',()=>{setLogVisibility(logVisibility=!logVisibility);});function setLogVisibility(bool){Array.from(output.getElementsByClassName('log')).forEach(ee=>{ee.style.display=bool ?'block':'none';e.innerText=bool ?'[log(on)]':'[log(off)]';});}setLogVisibility(logVisibility);});window.addEventListener('error',(evt)=>(addEntry(evt.error.stack)));function addEntry(string,category='error'){append(output,"<DIV class='entry "+category+"'/>",e=>{e.style.marginTop='0.5em';e.style.borderTop='1px solid #888';e.style.fontWeight=category=='error'?'bold':'';append(e,'<CODE/>',e=>{e.innerText=string;});});};const oldConsoleLog=console.log;console.log=function(...args){oldConsoleLog(...args);addEntry(args.join(' '),'log');};function testingIfErrorLogWorks_a(){testingIfErrorLogWorks_b();}function testingIfErrorLogWorks_b(){noSuchFunction();}setTimeout(testingIfErrorLogWorks_a,10);setTimeout(()=>console.log('LogTest'),20);setTimeout(testingIfErrorLogWorks_b,30);})();undefined;
我已将这些作为书签添加到 Google Chrome (Windows 10) 上,并同步到 iOS 和 Android。
在 Android 和 Windows 上,这两个脚本都按预期工作:
DebugSimple.js
用带有回溯和console.log
调用的错误日志替换页面的主体。DebugOverlay.js
广告 iframe 覆盖,其中错误记录得更清楚。
在 iOS 上,更简单的脚本DebugSimple.js
将按预期执行并记录错误,因此我知道错误正在 iOS 上被捕获,尽管输出的有用性不如 Android 和 Windows 10。这包括语法错误,例如javascript:};
在 URL 栏中输入 (语法错误)。
但是,如果我调用DebugOverlay.js
脚本,即使我从书签中手动复制粘贴它,也不会发生任何事情;DebugSimple.js
也不报告任何类型的错误。
我怀疑这可能与小书签的长度有关,因为这种行为似乎主要发生在大型小书签上;但无论如何,似乎很奇怪,根本没有任何东西可以表明原因。
在这一点上,我不知道如何进行;请记住,我没有任何 Mac 设备。
格式化的来源DebugSimple.js
document.body.innerHTML = '';
document.body.style.all = 'initial';
function putString(string) {
document.body.innerText += string;
}
const oldConsoleLog = console.log;
console.log = function(...args) {
putString('(log) ' + args.map(e => e.toString()).join(' '));
return oldConsoleLog(...args);
};
window.addEventListener('error', event => {
var msg = '\n(err) ';
msg +=
!event ? '!!event = ' + event :
!event.error ? '!!event.error = ' + event.error :
!event.error.stack ? '!!event.error.stack = ' + event.error.stack :
event.error.stack;
if(event && event.error) for(const key in event.error) {
msg += '\nevent.error.' + key + '=' + event.error[key];
}
putString(msg);
});
// Test error.
console.log("Log test.");
setTimeout(backtraceTest,10);
function backtraceTest(){ backtraceTest2(); }
function backtraceTest2(){ noSuchFunctionShouldExist(); }
格式化的来源DebugOverlay.js
// DOES NOT WORK IN CHROME WHEN PASTED TO THE CONSOLE.
// The console messes somehow with error events.
// Should work when executed as bookmarklet or 'javascript:' URI.
const highestZIndex = Math.max(
...Array.from(document.getElementsByTagName('*'))
.map(e=>window.getComputedStyle(e).zIndex)
.map(parseInt)
.filter(e => !isNaN(e)));
console.log(highestZIndex);
function append(parent, html, callback = undefined) {
var e = document.createElement('DIV');
parent.appendChild(e);
e.outerHTML = html;
e = parent.lastElementChild;
if(callback) callback(e);
return e;
}
const ifr = document.createElement('IFRAME');
document.body.prepend(ifr);
ifr.id = 'debugOverlay.js';
ifr.style.all = 'initial';
ifr.style.zIndex = highestZIndex + 1;
ifr.style.position = 'fixed';
ifr.style.left = '5%';
ifr.style.right = '5%';
ifr.style.width = '90%';
ifr.style.height = '90%';
ifr.style.opacity = '90%';
ifr.style.backgroundColor = '#ddd';
ifr.style.border = '1pt solid #888';
// Firefox requires content to be initialized.
ifr.contentDocument;
ifr.contentDocument.open();
ifr.contentDocument.close();
const header = append(ifr.contentDocument.body, "<DIV id='header'/>", e => {
e.style.position = 'static';
});
const closeButton = append(header, "<A href='#' id='closeButton'>[CLOSE]</A>", e => {
e.addEventListener('click', () => ifr.parentElement.removeChild(ifr));
});
const clearButton = append(header, "<A href='#' id='clearButton'>[CLEAR]</A>", e => {
e.addEventListener('click', () => {
output.innerHTML = '';
});
});
const output = append(ifr.contentDocument.body, "<DIV id='outputPane'/>", e => {
e.style.fontFamily = 'Sans';
});
append(ifr.contentDocument.body, "<DIV id='overScroll' style='height:30vh'/>");
var fontSizeScale = 0.8;
function setOutputFontSize(scale) {
output.style.fontSize = (fontSizeScale * 100) + '%';
}
setOutputFontSize(fontSizeScale);
const fontSizePlus = append(header, "<A href='#' id='fontSizePlus'>[LGR]</A>", e => {
e.addEventListener('click', () => {
setOutputFontSize(fontSizeScale *= 1.2);
});
});
const fontSizeMinus = append(header, "<A href='#' id='fontSizePlus'>[SML]</A>", e => {
e.addEventListener('click', () => {
setOutputFontSize(fontSizeScale /= 1.2);
});
});
const toggleLog = append(header, "<A href='#' id='toggleLog'>[log(on)]</a>", e => {
var logVisibility = true;
e.addEventListener('click', () => {
setLogVisibility(logVisibility = !logVisibility);
});
function setLogVisibility(bool) {
Array.from(output.getElementsByClassName('log')).forEach(ee => {
ee.style.display = bool ? 'block' : 'none';
e.innerText = bool ? '[log(on)]' : '[log(off)]';
});
}
setLogVisibility(logVisibility);
});
window.addEventListener('error', (evt) => (addEntry(evt.error.stack)));
function addEntry(string, category='error') {
append(output, "<DIV class='entry "+category+"'/>", e => {
e.style.marginTop = '0.5em';
e.style.borderTop = '1px solid #888';
e.style.fontWeight = category == 'error' ? 'bold' : '';
append(e, '<CODE/>', e => { e.innerText = string; });
});
};
const oldConsoleLog = console.log;
console.log = function (...args) {
oldConsoleLog(...args);
addEntry(args.join(' '), 'log');
};
// For testing.
function testingIfErrorLogWorks_a() { testingIfErrorLogWorks_b(); }
function testingIfErrorLogWorks_b() { noSuchFunction(); }
setTimeout(testingIfErrorLogWorks_a,10);
setTimeout(()=>console.log('LogTest'), 20);
setTimeout(testingIfErrorLogWorks_b,30);
解决方案
推荐阅读
- java - java.lang.IllegalStateException:指定的 firefox 二进制位置不存在或不是真实文件:/usr/bin/firefox 使用 GeckoDriver Selenium
- azure - Azure 发布管道:即使添加了替换镜像标签的步骤,Docker 镜像标签也不会被替换
- flutter - 如何在 Flutter android 10 中更新应用程序图标徽章?
- excel - 如何在动态 Excel ListObject 表中填充数据?
- android - RecyclerView 中的 OnClickListener 上的按钮并不总是可见
- php - Ubuntu 14.04 - PHP socket_create 不创建端口来监听
- kubernetes-helm - 根据 Helm(第一次)安装或升级有条件地设置值?
- laravel - 在 Laravel 中根据外键使列唯一
- python - 将 Python2 脚本移植到 Python3 - 结构库
- c++ - 在c ++中随机更改字符串中字母的位置