javascript 脚本如何进行“等待/sleep()”?

2015-11-10 14:41:40 +08:00
 leavic
最近在学 js ,拿几个网站写 grease monkey 脚本练手,发现一个问题是有些网站的数据并不是直接在 html 中呈现的,而是通过 js 加载的,也许这就是所谓的 ajax 吧。

现在问题是,如果我要用自己的脚本处理这部分数据,就必须保证这些数据被网站自己的脚本加载成功了才行,否则我的脚本是看不到这些数据的。

因为 ajax 很多都是异步加载的,所以就算是把函数绑定到 windows.onload 方法上也不一定能保证脚本加载完了数据,现在的方法只能是用 setTimeOut 做个固定延时,但体验不太好,而且不是稳妥的做法。

我希望的做法是用一个 while 循环检查页面内容是否加载成功,这个循环中,如果没有检测到内容,就让 js 脚本睡眠,类似 rtos 中线程主动释放 cpu 控制权一样。否则的话,这个循环就是个一直占用大量 CPU 资源的恶性循环,很容易让浏览器假死。

不过找了一圈好像没有看到这样的函数,我总不能为了实现个 sleep ,自己在 javascript 上写一套类 rtos 调度系统出来吧。我本来想用一堆10~100毫秒的setTimeOut来实现,结果发现这好像还是会让浏览器假死,似乎setTimeout并没有释放CPU资源。
15789 次点击
所在节点    JavaScript
39 条回复
leavic
2015-11-10 15:33:39 +08:00
@breeswish 不是这个问题,因为 alert 是绝对不会被执行的,问题出在 setTimeOut 是非阻塞的。
nisnaker
2015-11-10 15:35:54 +08:00
var t;
t = setInterval(function(){
if(check_something() == true) {
clearInterval(t);
// your funcs
}
}, 1000);


大概这样。
GtDzx
2015-11-10 15:38:15 +08:00
@leavic 建议你花个一天时间读读《 JavaScript The Definitive Guide 》,尤其是第 17 章 Handling Events 。浏览器端 JS 的事件驱动编程模型和一般的 C 语言程序有很大不同,我自己一开始也似懂非懂一知半解。与其针对一个具体例子分析来分析去,不如踏踏实实从头学习来的快。
frozen2013
2015-11-10 15:43:39 +08:00
额,你感到浏览器假死是因为 while ( true )生成了 n 多个 setTimeout,这个锅不能 setTimeout 来背.

用 settimeout 做定时器要这么写
function fn() {
if (check_something()===false) {
timer = setTimeout(fn, 100);
}
else {
//TODO
}
}
var timer = setTimeout(fn, 100);
leavic
2015-11-10 15:46:22 +08:00
@GtDzx 谢谢建议。

其实我自己用 C 写过简单的 RTOS ,所以调度系统对我来说是没什么难度的,用 RTOS 的思想做支撑,这些东西其实很容易理解,有点像练武的人打通任督二脉:)

我今天这个问题主要是没先检查 setTimeOut 函数是不是阻塞的,现在已经搞定了。
leavic
2015-11-10 15:46:53 +08:00
@frozen2013 对的,我改用 setInterval 就好了。
Biwood
2015-11-10 16:00:23 +08:00
用 while 循环不就阻塞了整个 JavaScript 线程么,本来就是单线程,你这么一搞别的 js 代码都无法执行了。用定时器也不是什么好办法,频率高的话一样很影响性能。应该会有一些比较 hack 的方法可以解决你的问题,但是我觉得这种操作太敏感了吧,直接捕捉别人网站的数据?
pagxir
2015-11-10 16:07:57 +08:00
很明显,以楼主目前的水平,很难跟他解释清楚。
leavic
2015-11-10 16:14:50 +08:00
@Biwood 只是过滤掉我不想要的内容
leavic
2015-11-10 16:16:13 +08:00
@Biwood 我用定时器坐下来效果很好了,因为本身操作量就很小。
xiumushenzuo
2015-11-10 17:20:21 +08:00
建议题主还是看一下 23 楼推荐的内容,这和 RTOS 并不同,并不是多线程多任务的问题。
你现在的方式的确可以达到效果,但消耗了很多浏览器资源,而且不够优雅,并不是 js 这个语言通用的解决方案。
leavic
2015-11-10 18:49:25 +08:00
@xiumushenzuo 谢谢,我会去看的。
FrankFang128
2015-11-10 18:55:38 +08:00
永远不要在 JS 实现 Sleep
maplerecall
2015-11-10 21:06:23 +08:00
在 js 中用循环和模拟 sleep 的方式判断是否加载完成是十分不对的, js 由于其特性与使用场景所需要的编程思想与 c 等非脚本语言是不太一样的。

lz 题目中描述的需求实际上是不需要任何 setTimeout 和 setInvertal 的,所要做的只是让这些 ajax 请求加载完成后来主动执行需要的操作。 23 楼的内容应该会有不少帮助~
maplerecall
2015-11-10 21:17:57 +08:00
@maplerecall 啊抱歉没看清楚前提_(:3 」∠)_
如果是 grease monkey 这种插入式脚本可以通过监听 DOMNodeInserted 事件来判断是否已处理完请求到数据
不过我记得这个似乎可以在页面加载前就执行?也许可以直接复写浏览器的 XMLHttpRequest 来直接获取请求数据 XD
leavic
2015-11-10 21:29:14 +08:00
@maplerecall 但这还有个问题,例如京东页面上的无货提示,就是 js 加载出来的,但并不是一定会有无货提示出现(碰上全有货的话),这种情况下,是不是 DOMNodeInserted 事件就不一定发生了。
zhuangzhuang1988
2015-11-10 21:41:39 +08:00
用下老赵的 winjs
dqh3000
2015-11-10 22:09:06 +08:00
其实我很想说等到 es6 的 yield 或者 es7 的 async 就好了……

不过大家的回答好像都跟我想的不一样……

@FrankFang128
SuperMonster009
2019-04-19 08:14:11 +08:00
mdn 提到可以用 promise

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

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

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

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

© 2021 V2EX