JS在线运行工具点自带的异步示例,面板上只会出现第一行,剩下6条去了别处
本文目录
- 先说最要命的那条:异步输出根本没进面板
- 4行代码就能验出来
- 为什么会这样
- 拿工具自带的示例做对照,一点就露馅
- 三个示例的实测结果
- 同一段代码在浏览器控制台里跑是什么样
- 为什么这个体验特别容易被误读
- 7个示例里有几个受影响
- 这条限制影响多大
- 怎么绕过去
- 统计条也跟着一起骗人
- 耗时只算同步部分
- 输出行数只数进了面板的
- 左边那列行号,从第5行起就对不上了
- 先看现象
- 量一下
- 根因是一行样式声明
- 怎么快速自查
- 为什么这种问题能存活这么久
- 没有沙箱,没有超时,一个死循环就能锁死整页
- 代码在哪里跑
- 换成死循环会怎样
- 代码和工具页面共享同一个文档
- 实际使用中怎么防
- 面板上的对象,和你在真控制台里看到的不是一回事
- 实测一组常见值
- 数组里的undefined那条最阴
- 时间对象那条也有点绕
- 循环引用那条要单独说
- 还有个排版上的小别扭
- 输入1加1什么都不显示,这不是缺陷
- 两种写法差在哪
- 顺带说个容易混的点
- 报错不给行号,50行代码里自己找
- 变量不跨次保留,但有一种写法会留下来
- 实测三种声明方式
- 那个口子有多大
- 那么这个工具适合拿来做什么
- 适合的场景
- 不适合的场景
- 一个提高效率的小习惯
- 一条通用建议
- 常见问题解答
- 为什么点了Fetch API示例只显示一行就没了?
- 面板下方显示的耗时可以用来比较性能吗?
- 左边的行号为什么和代码对不上?
- 写了死循环怎么停下来?
- 为什么打印Map和Set显示的是空对象?
- 输入1加1为什么没有任何输出?
- 上一次运行声明的变量还在吗?
- 权威参考资料
摘要:这个工具最关键的一条限制,用它自己的示例按钮就能验出来:点开自带的Async/Await示例,代码里有7处输出,面板上只会出现1条。不是请求失败,是它在同步代码跑完的那一瞬间就把控制台还回去了,后面所有回调的输出全落到了浏览器自己的控制台里。
下面把这条以及行号错位、主线程无保护、对象显示失真几处逐一量出来,最后给一份它适合干什么、不适合干什么的清单。
先说最要命的那条:异步输出根本没进面板
在线跑一段JavaScript,这类工具满大街都是。真正拉开差距的不是能不能跑,是跑完之后你看到的东西全不全。
JS在线运行工具把代码编辑器、控制台面板、7个示例按钮摆在一屏里,粘贴即跑,不用装环境。这个形态本身很实用,尤其适合手边没有开发环境、只想验一个小东西的时候。但它有一条限制严重到会让人误判自己的代码——而且这条限制在页面上一个字都没提。
4行代码就能验出来
把下面这段贴进去,点运行:
console.log('① 同步:这行在函数体里直接跑');
setTimeout(function(){ console.log('② 异步:0毫秒的定时器回调'); }, 0);
Promise.resolve().then(function(){ console.log('③ 微任务:Promise 的 then'); });
console.log('④ 同步:最后一行同步代码');4条输出,面板上只会出现2条:①和④。②和③永远不会出现,等多久都不会。运行返回的瞬间面板是2条,等上120毫秒再看,还是那2条。
那两条不是慢,是丢了。它们确实执行了,输出去了浏览器自带的开发者工具控制台,只是没有进这个面板。你按F12打开控制台,会发现它们安安静静躺在那儿。
为什么会这样
这类工具捕获输出的通用做法是:运行前把console.log换成自己的函数,运行后再换回来。中间这段时间里的所有输出都会被截住,显示到面板上。这个套路本身没毛病,几乎所有在线运行工具都这么干。
问题出在还回去的时机。它是在用户代码同步执行完毕、函数返回的那一行立刻还原的。而定时器的回调、Promise的后续处理、请求的响应处理,全都排在同步代码之后才执行。等它们真正跑起来时,console.log早已经变回原生的了。
实测确认了这一点:运行返回后立即检查,console.log的源码里已经是原生标记,说明还原动作已经完成。而此时连微任务队列都还没开始跑——微任务的优先级已经是所有异步里最高的了,依然赶不上。
换个角度说,这个捕获窗口的宽度,正好等于同步代码的执行时长。你的代码同步部分跑得越快,这个窗口关得越早。写一段几毫秒就跑完的同步代码,窗口开合之间几乎没有给异步任务留下任何余地。
拿工具自带的示例做对照,一点就露馅
上面那段是我构造的,多少有点刻意。更有说服力的是拿它自己的示例按钮试——那是作者亲手放上去、默认认为能正常演示的代码。
三个示例的实测结果
| 示例按钮 | 代码里的输出语句数 | 面板实际收到 | 面板上唯一那条的内容 |
|---|---|---|---|
| Async/Await | 7 | 1 | 开始请求... |
| Fetch API | 4 | 1 | 正在请求API... |
| 算法示例(纯同步) | 4 | 5 | 全部正常显示 |
前两行和第三行构成了一组干净的对照。纯同步的算法示例,4条输出加1条计时结果,5条全都在;两个异步示例,各自只剩开头那一句。
注意第三行那个5比4大。算法示例里用了计时功能,计时结束时会额外打印一条耗时记录,所以面板收到的比源码里的输出语句还多一条。这一条恰恰说明捕获机制本身是好使的,只要你在同步窗口内打印,一条都不会漏。
同一段代码在浏览器控制台里跑是什么样
把那4行贴进浏览器自己的开发者工具控制台,回车。你会看到①和④先出现,紧接着③出现,最后②出现。四条一条不少,而且顺序清楚地演示了微任务优先于宏任务这件事。
这个对比挺能说明问题:同样的代码、同样的浏览器引擎,差别只在于谁来接管输出。工具的面板不是跑得不对,是听得不全。
顺序这件事本身也值得留意。很多人以为设成0毫秒的定时器会立刻执行,实际它排在所有微任务之后。要理解异步代码的执行次序,这4行比大段文字管用,可惜在这个面板里正好看不到。
为什么这个体验特别容易被误读
你点了Fetch API示例,看到面板上写着正在请求,然后就没动静了。第一反应多半是网络不通、接口挂了、或者跨域被拦。这三个猜测都很合理,也都很难当场排除——尤其那个示例请求的是境外的公开测试接口,在国内网络环境下确实经常连不上。
于是你可能会花十几分钟去查网络、换接口、看跨域策略,最后发现请求其实早就成功了,数据也拿到了,只是打印结果的那几行没人接。一个把成功伪装成失败的界面,比一个明确报错的界面更耗时间。
7个示例里有几个受影响
数了一遍工具自带的示例:基础输出、数组操作、算法演示、正则匹配、JSON处理这5个是纯同步的,能正常显示;请求接口和异步等待这2个是异步的,都只能看到开头。操作页面元素那个介于两者之间,取决于代码里有没有用到延时。
比例上看不算严重,7个里坏2个。但从使用频率看,恰恰是异步那两个最有演示价值——同步代码大家心里都有数,异步的执行顺序才是真正需要跑一跑才明白的部分。
这条限制影响多大
取决于你拿它干什么。测一个正则、算一段字符串处理、验证数组方法的返回值,这些都是同步的,完全不受影响。但凡涉及定时器、接口请求、Promise链、await,面板就只能给你看个开头。
现代JavaScript里异步的比重有多高不用多说,一段业务代码里不含任何异步反而是少数情况。所以更准确的说法是:它是一个同步表达式验证器,不是一个JavaScript运行环境。知道这个定位,用起来就不会踩坑,也不会对它有不切实际的期待。
怎么绕过去
如果非要在这个面板里看到异步结果,有个笨办法:把异步逻辑改写成先把结果攒起来、最后同步打印。但仔细想就会发现这条路是死的——攒到什么时候才算完?判断完成的那个时刻本身就在异步回调里,你在那里打印,照样打印不出来。
所以真正的答案是:别绕,直接按F12打开浏览器自己的控制台看。那些输出都在那儿,一条不少,格式还更好。这个工具的面板只是个方便的展示层,浏览器的控制台才是真正的输出终点。
统计条也跟着一起骗人
面板下方有一行统计:运行次数、耗时、输出行数。前面那段4条输出的代码跑完,它显示的是耗时3.2毫秒、输出行数2。
两个数字都对不上实际情况,而且错的方向一致——都在系统性地低估。
耗时只算同步部分
计时是在同步执行前后各取一次时间戳,差值就是耗时。异步任务还排在队列里没跑,计时就已经结束了。
拿Fetch API示例来说,面板会告诉你耗时几毫秒,而那个网络请求真正完成可能是几百毫秒之后的事。这个数字衡量的是发起的成本,不是完成的成本。拿它比较两段代码的性能,只要涉及异步就完全没有意义。
更微妙的是,同步代码的耗时本身也不太适合用来做性能判断。现代JavaScript引擎会做即时编译和各种优化,同一段代码跑第一次和跑第十次的耗时能差好几倍。要认真测性能,得跑很多次取分布,而不是看单次的一个读数。
输出行数只数进了面板的
同理,那2条是面板收到的条数,不是代码实际打印的条数。异步示例里它会显示输出行数1,而代码写了7条。
这两个数字本身没有说谎,它们如实反映了面板知道的事。麻烦在于用户会把它们当成代码的运行结果来读。一个显示得理直气壮的错误数字,比没有数字更容易误导人。
假如面板在这里加一句提示,比如异步输出不会被统计,问题就小得多。现在的做法是把一个局部的观测值当成全局的结论展示出来,而观测口径从来没被说明过。这类问题在数据类工具里特别常见——不是算错了,是没告诉你算的是什么。
左边那列行号,从第5行起就对不上了
这是个纯视觉问题,但它每天都在发生,而且从工具上线到现在一直是这样。
先看现象
打开工具,编辑器里有段19行的默认代码。左边的行号列,前几行是这样排的:第一行显示的是1和2挤在一起,第二行是3和4,第三行是5和6,一直到9和10,然后从11开始才变成一行一个。
于是代码第4行对应的行号显示成了7和8。你想告诉同事第12行有问题,对着行号列数过去,指到的是别的地方。两个人隔着屏幕对不上号,最后只能靠念代码内容确认。
量一下
用范围对象量出行号列文本实际占据的视觉行数:
| 指标 | 读数 |
|---|---|
| 代码真实行数 | 19 |
| 行号文本里的换行符数量 | 19 |
| 行号列渲染出的视觉行数 | 14 |
| 前4个视觉行的宽度 | 各21.5像素 |
| 第6个起的视觉行宽度 | 各14.3像素 |
换行符一个不少地写进去了,渲染出来却少了5行。宽度这两个数把真相说透了:21.5像素正好是一个数字、一个空格、再一个数字;14.3像素正好是两个数字。也就是说个位数的行号两个挤一行,两位数的一行一个。
算一下也对得上:1到9这9个个位数,两两一组占了5行(最后一行是9和10配对),10到19这10个两位数各占一行,5加9正好14。
根因是一行样式声明
行号是把1、2、3这些数字用换行符拼成一长串,整体塞进一个元素里。要让换行符真的换行,这个元素必须声明保留空白。
实测两个元素的计算样式,代码文本框那边是保留模式,行号列这边是折叠模式,而两者的行高完全一致,都是22.1像素。折叠模式下换行符被当成普通空格,整串行号变成一段连续文本,在44像素宽的窄列里自动换行重排。
这是一对一错的完美对照:同一个样式表里,文本框那边写对了,行号列这边漏了。改法就是补上那一行声明,一个属性的工作量。
顺带一提,滚动同步那个功能也跟着废了。代码往下滚时行号列会同步滚动,但两边的内容高度对不上,滚得越远偏差越大。
怎么快速自查
不用量像素也能确认:随便往编辑器里贴一段超过10行的代码,看行号列最后一个数字是不是等于你的代码行数。对不上就是这个毛病。
或者更省事,在代码末尾敲几个空行,看行号有没有跟着往下长。折叠模式下新增的换行符照样会被吃掉,行号列的最后一个数字会变,但位置对不上。
为什么这种问题能存活这么久
因为它不影响功能。代码照样能编辑,运行照样出结果,只有行号是错的。而行号这东西大多数时候没人会特意去核对,除非报错信息给了行号让你去找——偏偏这个工具的报错又不给行号,于是连暴露的机会都没有。
这算是个小小的黑色幽默:两个缺陷凑在一起,反而互相掩护了。
没有沙箱,没有超时,一个死循环就能锁死整页
这一条是使用风险,不是显示问题。
代码在哪里跑
用户代码被包成一个函数直接在页面主线程里执行。没有独立线程隔离,没有内嵌框架沙箱,也没有任何超时中断机制。
做了个安全的实验:写一段忙等400毫秒的代码(不是死循环,会自己结束),同时用动画帧回调数这期间浏览器渲染了多少帧。
| 观测项 | 读数 |
|---|---|
| 同步占用主线程 | 400.3毫秒 |
| 期间渲染的动画帧数 | 0 |
| 是否有独立线程隔离 | 无 |
| 是否有超时保护 | 无 |
400毫秒里一帧都没渲染出来。按每秒60帧算,正常应该有24帧。整个页面在这段时间是冻住的,按钮点不动,滚动也不响应,光标闪烁都停了。
换成死循环会怎样
把条件改成永远为真,页面就永久冻结了。没有任何机制能把它停下来——停止按钮不存在,就算存在也点不动,因为处理点击事件的也是同一个主线程。
浏览器过一会儿可能会弹出页面无响应的提示,问你要不要等待或者结束。选结束就是关掉这个标签页。唯一的出路就是这个,没保存的代码跟着一起没。
代码和工具页面共享同一个文档
还有个连带的后果:既然代码在页面主线程里跑,它操作的文档对象就是工具页面本身。工具自带的操作页面元素示例,改的其实是这个页面的元素。
示例代码本身很克制,只是创建了临时元素做演示,不会破坏什么。但如果你贴一段真实业务里的页面操作代码,比如按类名批量删除节点,删掉的就是工具页面上的东西。刷新能恢复,只是当场会有点懵。
实际使用中怎么防
- 写循环时先把终止条件写完整再点运行,别指望能中途叫停
- 递归函数先想清楚出口,栈溢出反而是好事(会抛错停下来),真正麻烦的是那种一直增长但不溢出的情况
- 重要的代码别只存在这个编辑器里,它没有自动保存,页面一关就没了
- 要跑不确定会不会失控的代码,用浏览器自己的开发者工具,至少那里能刷新页面止损
- 先用小数据量跑通,再改成正式的数据量,别一上来就喂十万条
这不是苛责。纯前端的在线运行工具要做真正的隔离,得把代码丢进独立线程或者沙箱框架,通信、输出捕获、超时中断都要重写一遍,工作量翻好几倍。而且独立线程里没有文档对象模型,工具自带的那个操作页面元素的示例就跑不了了。取舍是明摆着的,知道它没有这层保护,自己绕开就是了。
面板上的对象,和你在真控制台里看到的不是一回事
输出的格式化用的是JSON序列化。这条路对普通对象和数组够用,碰到几类特殊值就会失真。
实测一组常见值
| 你打印的 | 面板上显示的 | 问题 |
|---|---|---|
| new Map带两组键值 | {} | 键值全丢 |
| new Set带三个元素 | {} | 元素全丢 |
| 正则表达式 | {} | 整个变成空对象 |
| [1, undefined, 3] | [1, null, 3] | undefined变成了null |
| 含循环引用的对象 | [object Object] | 整个塌成一个字符串 |
| new Date(0) | 带引号的标准时间串 | 不是本地时间格式 |
| 负零 | 0 | 负号丢失 |
前三行是同一个原因:这几种内置类型没有可枚举的自有属性,序列化看过去就是个空壳。这是序列化本身的既定行为,不是工具写错了,但显示成一对空花括号确实会让人以为自己的集合是空的。
正则那一行尤其容易咬人,因为这个工具自带一个正则匹配的示例按钮。在里面打印一个正则对象,得到的是空对象——而你点进这个示例,多半就是想看看正则长什么样。
数组里的undefined那条最阴
数组元素是undefined时会被转成null。这两个值在JavaScript里含义完全不同:一个是没赋值,一个是明确的空值。调试数据处理逻辑时,你可能正在找的就是哪个位置漏了赋值,而面板把它显示成了null,线索直接断了。
更麻烦的是这个转换很难被察觉,因为null看上去是个合法的、说得通的值。你不会怀疑它,只会顺着这个错误的信息往下找。
时间对象那条也有点绕
打印一个时间对象,面板显示的是带引号的标准时间串,那是国际标准格式、以零时区表示的。而浏览器控制台显示的是本地时区的可读格式,还会标出星期几。
差别不只是好不好看。调试时区相关的逻辑时,面板给你的永远是零时区的读数,你得自己在脑子里加8小时。本来想验证的就是时区转换对不对,工具却把时区信息统一抹平了,这一验等于白验。
循环引用那条要单独说
对象自己引用自己时,序列化会直接抛异常。工具捕获了这个异常,退回到普通的字符串转换,结果就是那个经典的[object Object]。
真实浏览器控制台在这里会给你一个可展开的树,还会用特殊标记指出循环的位置。这个差距在调试嵌套数据结构时相当明显——树形数据、双向链表、带父指针的节点,这些结构天然带循环引用。
还有个排版上的小别扭
序列化用了两个空格的缩进,所以数组会被竖着展开。工具自带的算法示例里打印一个8个元素的数字数组,面板上占了整整10行。真实控制台会把它压成一行,前面还标着元素个数。
内容没错,就是把面板撑得很长。排序算法这类要打印中间步骤的场景,每打印一次数组就是十几行,跑完一遍得滚好几屏。要对比排序前后的差异,来回滚动挺累的。
输入1加1什么都不显示,这不是缺陷
新手最容易困惑的一处。在浏览器自带的控制台里敲1 + 1,回车就显示2。在这里输入同样的内容点运行,面板一片空白,什么都没有。
两种写法差在哪
输入1 + 1,面板完全空白,没有任何输出,连一条提示都没有。改成return 1 + 1,面板立刻出现一条标着RETURN的记录,值是2。
差别在于这个工具不是读取求值输出循环。浏览器控制台是那种模式:你输入什么它就求值什么,然后自动把结果显示出来。而这个工具是把你的代码整段包进一个函数体里执行。函数体里写一个孤零零的表达式,语法上合法,但值被丢掉了,除非你显式写return。
工具确实处理了返回值——有返回值时会显示一条RETURN标记的记录。只是它的说明文档从头到尾没提过要写return这件事,7个示例代码里也全都是打印语句,没有一个用返回值的。于是这个能力等于藏起来了。
说明与实现对不上,在这类工具页面里算是通病。同一批里那款生成网站图标的,常见问题里写着生成的代码已经包含矢量图标声明,实测把整段代码搜一遍是零命中,细节在Favicon生成器给的10个图标文件里真正上场的只有一张那篇里。文档是人写的,实现是另一个时间点的人写的,两边不同步太常见了。
顺带说个容易混的点
在函数体的顶层写return是合法的,这一点很多人不确定。它和在模块顶层写return不一样,后者会报语法错误。因为这里的代码本来就被包在函数里,return有明确的归属。
所以规矩是:想看什么,要么打印它,要么return它。直接写表达式等于什么都没写。
报错不给行号,50行代码里自己找
故意在第3行写个语法错误,前两行完全正常。运行之后面板给出的是一行错误:类型是语法错误,消息是遇到了意外的分号。
就这一行。没有行号,没有列号,没有调用栈。
错误处理只取了异常的名称和消息两个字段,堆栈信息整个丢掉了。而语法错误在代码解析阶段就抛出来了,连第1行都还没执行——这也是为什么前两行明明正常,你却看不到它们的输出。
代码只有几行时无所谓,扫一遍就行。写到五六十行,一个位置不明的语法错误能耗掉相当长的时间,尤其在行号列还对不上的情况下。运行时错误也一样,比如某个变量拼错了,只告诉你这个名字未定义,不告诉你在哪一行。
对照一下,浏览器自己的控制台在这里会给出精确到行列的位置,还能点击跳转到出错的那一行。这也是前面那个建议的另一个理由:真要认真调试,还是回到开发者工具里去。
粘贴代码之前先过一道格式化,能提前暴露一部分结构问题,比如括号没配对。工具自己带了格式化按钮,多语言格式化工具的边界在代码格式化工具支持十几种语言,是每种都真懂吗?那篇里有过一次实测。
变量不跨次保留,但有一种写法会留下来
这一节讲的是运行之间的隔离程度,关系到你会不会被上一次的残留坑到。
实测三种声明方式
第一次运行声明三个变量,第二次运行检查它们还在不在。结果是:用var声明的和用let声明的都已经消失,而显式挂到全局对象上的那个仍然存在。
前两种的行为是好事:每次运行互不干扰,不会出现上次的变量污染这次的情况。代码被包在函数体里,函数一返回作用域就销毁了,连带里面的所有声明。
这一点比某些在线工具强。有些实现直接用全局求值,跑两次同一段带const声明的代码就会报重复声明的错,得刷新页面才能继续。这个工具没有这个毛病。
那个口子有多大
显式写到全局对象上的东西会一直留着,直到刷新页面。实测还确认了函数体里的this指向全局对象,这意味着用户代码和工具页面自身的脚本共享同一个全局环境。
理论上你可以覆盖掉工具自己的函数,比如把它的运行函数改成别的东西,工具就不工作了。刷新一下就恢复,没什么破坏性,但足以说明这里确实没有隔离。
实际使用中要注意的只有一点:如果你的代码往全局挂了东西,多跑几次可能会互相影响。调试到一半发现行为诡异,第一反应应该是刷新页面重来,而不是怀疑自己的逻辑。
那么这个工具适合拿来做什么
把上面的限制折过来看,它的适用边界其实相当清晰。
适合的场景
- 验证一个正则表达式在特定字符串上的匹配结果
- 试数组和字符串方法的返回值,比如某个方法到底改不改原数组
- 算一段纯计算逻辑,排序、去重、格式转换这类
- 把一段从别处抄来的同步代码跑一遍看看输出
- 手边没有开发环境时,快速验证一个语法细节
- 给别人演示一段短代码的效果,一个链接就能共享环境
不适合的场景
- 任何带定时器、请求、Promise的代码——面板只给你看开头
- 性能对比——耗时数字不含异步部分,单次读数也不可靠
- 调试语法错误——不给行号,行号列本身还对不上
- 跑不确定会不会失控的循环——没有中断机制
- 需要看清集合类对象内部结构的场景——显示成空对象
- 需要保存或者持续迭代的代码——没有自动保存
一个提高效率的小习惯
既然它没有自动保存,验完一段有价值的代码顺手点一下下载按钮,会存成本地文件。比起下次从头再写一遍,这个动作只花一秒。
另一个习惯是把要验的东西尽量缩到最小。不要把整个函数搬过来,只留下你怀疑的那两三行加上必要的输入。范围越小,同步执行越快,前面提到的那些限制就越碰不到。
一条通用建议
把这类在线运行工具当成草稿纸,不当成工作台。草稿纸的价值是随手可得、不用准备,验个小东西比打开编辑器快得多。但凡事情复杂到需要看调用栈、需要看异步时序、需要反复迭代,就该换地方。
判断标准可以很简单:如果你打算在这里待超过五分钟,那多半选错工具了。
保哥自己用这类工具最多的场景是核对一个方法的边界行为,比如某个参数传负数会怎样、空数组调用某方法返回什么。这种问题查文档要翻半天,跑一次两秒钟出结果。至于调试真实业务代码,那还是老老实实开编辑器。
顺带一提,同一批工具里那款在线改CSS的,也有类似的定位问题——它输出的不是完整样式表而是一份差异清单,细节在CSS在线编辑器生成的不是完整样式,而是一份相对默认值的差异清单里。工具好不好用,往往取决于你有没有搞清楚它到底在给你什么。
⚡ 动手试试:JS在线运行工具
粘贴代码按Ctrl加回车就跑,控制台输出、错误捕获、代码格式化、7个现成示例都在同一屏里,不用装任何环境。验个正则、试个数组方法,比打开编辑器快得多。
保哥自研免费在线工具,浏览器打开就能用。
常见问题解答
为什么点了Fetch API示例只显示一行就没了?
因为异步回调里的输出没有被面板捕获。工具在同步代码执行完毕的瞬间就把控制台方法还原成原生的,而请求的响应处理排在之后才跑,那时已经没人接管输出了。实测该示例代码里有4处输出语句,面板只收到1条。请求本身多半是成功的,按F12打开浏览器控制台能看到完整结果。
面板下方显示的耗时可以用来比较性能吗?
只有纯同步代码可以,而且单次读数也不太可靠。计时是在同步执行的前后各取一次时间戳,异步任务还在队列里没跑,计时就结束了。带请求或定时器的代码会显示一个很小的数字,那是发起的成本不是完成的成本。要认真测性能得跑很多次看分布。
左边的行号为什么和代码对不上?
行号列缺少保留空白的样式声明,换行符被当成普通空格处理,整串行号在44像素宽的列里自动换行重排。实测19行代码只渲染出14个视觉行,个位数行号两个挤一行、两位数一行一个。同一个样式表里代码文本框那边是写对的,只有行号列漏了这一行。
写了死循环怎么停下来?
停不下来,只能关掉标签页。代码在页面主线程里直接执行,没有独立线程隔离也没有超时中断。实测一段400毫秒的忙等期间浏览器渲染了0帧,页面完全冻结,按钮点不动。未保存的代码会一起丢失,所以重要内容别只放在这个编辑器里。
为什么打印Map和Set显示的是空对象?
输出格式化走的是JSON序列化,而这几类内置对象没有可枚举的自有属性,序列化出来就是一对空花括号。这是序列化的既定行为,不是工具的实现错误。要看内容得先手动转换,比如把Map展开成数组再打印。正则对象也是同样的情况。
输入1加1为什么没有任何输出?
代码被整段包进一个函数体里执行,函数体里的孤立表达式语法合法但值会被丢弃。写成return加上表达式就能看到一条RETURN标记的结果。想看什么就打印它或者return它,直接写表达式等于没写。工具的说明文档没提过这一点,示例代码里也没有用到返回值的。
上一次运行声明的变量还在吗?
用var和let声明的都不在,函数返回时作用域就销毁了,每次运行互不干扰。但显式挂到全局对象上的属性会保留到页面刷新为止。实测函数体里的this指向全局对象,用户代码和工具页面共享同一个全局环境,调试出现诡异行为时刷新页面最省事。
权威参考资料
本文标题:《JS在线运行工具点自带的异步示例,面板上只会出现第一行,剩下6条去了别处》
本文链接:https://zhangwenbao.com/js-runner-async-console-linenum-blocking-guide.html
版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0