油猴中使用 GM_xmlhttpRequest 的诡异情况

2021-06-09 20:31:08 +08:00
 zhuzhuaini

此 BUG 复现率百分之一百

代码如下:

for(var i=0;i<10;i++){

GM_xmlhttpRequest({

                          url: "http://www.qq.com/",
                          
                          responseType: "document",
                          
                          headers:{'overrideMimeType': 'text/html;charset=gb2312'},
                          
                          onload:
                          
                      function(res){
                      
                          console.log(i)
                          
                          },
                          
                });}
                

我在油猴中使用此代码,但是输出并不是理想情况:

按代码执行来说 应该进入 For 循环后 访问 qq,获取到 QQ 的源代码然后打印当前循环次数,然后自增 i,进入下一次循环

理想情况打印的内容应该为 0-1-2....-9

但事实却是只会输出 10 个 10. 如图: https://www.hualigs.cn/image/60c0b3a27dd2c.jpg

而我如果稍加修改 将输出语句写在 GM_xmlhttpRequest 外面,for 循环的里面,则没有问题,如图: https://www.hualigs.cn/image/60c0b4086faa3.jpg

所以我认为就是 GM_xmlhttprequest 的问题,但是我不清楚这是 bug 还是什么别的原因导致的,有大佬知道吗?

2088 次点击
所在节点    JavaScript
14 条回复
hgc81538
2021-06-09 20:44:23 +08:00
for(var i=0;i<10;i++){

(function(i){

GM_xmlhttpRequest({

url: "http://www.qq.com/",

responseType: "document",

headers:{'overrideMimeType': 'text/html;charset=gb2312'},

onload: function(res){

console.log(i)

},

});

})(i);

}
wangsongyan
2021-06-09 20:44:45 +08:00
onload 是回调函数,异步执行
zhuzhuaini
2021-06-09 20:50:51 +08:00
@hgc81538 用了这个之后,行是行了,但感觉他不是顺序执行啊,输出的是乱序的
@wangsongyan 那怎么让他 不异步呢。。我就想让他 按顺序 一点点的干活
zhuzhuaini
2021-06-09 21:10:51 +08:00
@hgc81538 虽然顺序是乱的,但是好像没什么问题 能不能讲解下 (function(i)和最后的(i); 是啥作用
aloxaf
2021-06-09 21:22:25 +08:00
zhuzhuaini
2021-06-09 21:33:17 +08:00
@aloxaf 全英文。。。很不友好....
OHyn
2021-06-09 21:35:03 +08:00
onload 是回调函数,异步执行,当它执行的时候,for 循环已经结束,i 的值已经是 10.
你把 var 改成 let 可解决问题。
这俩东西的作用域有区别。
zhuzhuaini
2021-06-09 21:37:42 +08:00
@OHyn 刚刚试了下 var 改 let 似乎会引起别的问题(不过 onload 倒是没问题了) 我目前用了 L1 的方法 暂时没发现什么 BUG
knives
2021-06-10 00:04:14 +08:00
异步转伪同步的话,上 Promise chain 吧,用 await 语法来实现会比较简洁。
Yvette
2021-06-10 04:49:18 +08:00
需要看中文直接搜闭包也可以
muzuiget
2021-06-10 08:21:53 +08:00
老生常谈,GM_xmlhttpRequest 是异步函数, 用 Promise 和 await 解决。
linyinma
2021-06-10 09:27:52 +08:00
一般浏览器 JS 执行引擎是单线程:“事件驱动”, 调用 GM_xmlhttpRequest 是将消息留到事件队列,因此这个 for 循环只是把事件丢到队列中,等待本事件完成退出以后,JS 引擎线程再从事件队列处理处理刚丢进去的 GM_xmlhttpRequest 事件;
no1xsyzy
2021-06-10 09:30:16 +08:00
其实你了解下 CPS[1] 也就清楚怎么写了,不过这是个比较抽象的概念,实际工程上也不一定非得理解 CPS
简单地说,你这样 for(...){xhr({..., onload:x=>...})} 会同时发起十个续延,它们会产生某种竞态导致结果顺序不一致。
JS 的 var 关键词会传递同一个 ref alias,换 let 就会产生十个不同的 trn alias 了。当然,JS 的 refcap 并没有那么精确。

[1]: Continuation-Passing Style
Rhilip
2021-06-10 16:09:36 +08:00
这不是油猴的问题,是你对 js 异步不了解。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/782499

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX