JS在线运行工具点自带的异步示例,面板上只会出现第一行,剩下6条去了别处

JS在线运行工具点自带的异步示例,面板上只会出现第一行,剩下6条去了别处
张文保 26 分钟阅读 2,176 阅读
本文目录
  1. 先说最要命的那条:异步输出根本没进面板
  2. 4行代码就能验出来
  3. 为什么会这样
  4. 拿工具自带的示例做对照,一点就露馅
  5. 三个示例的实测结果
  6. 同一段代码在浏览器控制台里跑是什么样
  7. 为什么这个体验特别容易被误读
  8. 7个示例里有几个受影响
  9. 这条限制影响多大
  10. 怎么绕过去
  11. 统计条也跟着一起骗人
  12. 耗时只算同步部分
  13. 输出行数只数进了面板的
  14. 左边那列行号,从第5行起就对不上了
  15. 先看现象
  16. 量一下
  17. 根因是一行样式声明
  18. 怎么快速自查
  19. 为什么这种问题能存活这么久
  20. 没有沙箱,没有超时,一个死循环就能锁死整页
  21. 代码在哪里跑
  22. 换成死循环会怎样
  23. 代码和工具页面共享同一个文档
  24. 实际使用中怎么防
  25. 面板上的对象,和你在真控制台里看到的不是一回事
  26. 实测一组常见值
  27. 数组里的undefined那条最阴
  28. 时间对象那条也有点绕
  29. 循环引用那条要单独说
  30. 还有个排版上的小别扭
  31. 输入1加1什么都不显示,这不是缺陷
  32. 两种写法差在哪
  33. 顺带说个容易混的点
  34. 报错不给行号,50行代码里自己找
  35. 变量不跨次保留,但有一种写法会留下来
  36. 实测三种声明方式
  37. 那个口子有多大
  38. 那么这个工具适合拿来做什么
  39. 适合的场景
  40. 不适合的场景
  41. 一个提高效率的小习惯
  42. 一条通用建议
  43. 常见问题解答
  44. 为什么点了Fetch API示例只显示一行就没了?
  45. 面板下方显示的耗时可以用来比较性能吗?
  46. 左边的行号为什么和代码对不上?
  47. 写了死循环怎么停下来?
  48. 为什么打印Map和Set显示的是空对象?
  49. 输入1加1为什么没有任何输出?
  50. 上一次运行声明的变量还在吗?
  51. 权威参考资料

摘要:这个工具最关键的一条限制,用它自己的示例按钮就能验出来:点开自带的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/Await71开始请求...
Fetch API41正在请求API...
算法示例(纯同步)45全部正常显示

前两行和第三行构成了一组干净的对照。纯同步的算法示例,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个现成示例都在同一屏里,不用装任何环境。验个正则、试个数组方法,比打开编辑器快得多。

保哥自研免费在线工具,浏览器打开就能用。

→ 打开JS在线运行工具

常见问题解答

为什么点了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

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交