V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
FaiChou
V2EX  ›  JavaScript

js 如何优化这种情形: 无限状态切换

  •  
  •   FaiChou · 2021-12-19 18:14:14 +08:00 · 2281 次点击
    这是一个创建于 858 天前的主题,其中的信息可能已经有所发展或是发生改变。
    function start() {
      var screen = captureScreen();
      // 出现弹框, 干掉弹框
      if (screen.find(ALERT_BUTTON) {
      	click(ALERT_CLOSE_BUTTON);
        start();
      }
      // 如果有返回按钮, 点击返回
      if (screen.find(BACK_BUTTON) {
        click(BACK_BUTTON);
        start();
      }
      // 如果不在首页(首页没有高亮选中), 点击回到首页
      if (screen.find(HOME_BUTTON_UNHIGHLIGHT) {
        click(HOME_BUTTON_UNHIGHLIGHT);
       	start(); 
      }
      // 在首页了, 有“喜欢按钮”
      if (screen.find(LIKE_BUTTON) {
        click(LIKE_BUTTON);
        swipeNextVideo();
        sleep(5000);
        start();
      }
    }
    
    setInterval(function() {
      if (currentPackage() !== 'PACKAGE_NAME') {
        launch('PACKAGE_NAME');
      }
    }, 1000*60*10) // 10 分钟检查一次程序是否被杀死, 程序不在运行就重新打开
    
    start();
    

    以上是脚本程序的大概逻辑:

    打开某视频软件, 如果有弹框, 干掉弹框, 如果不在首页, 返回首页, 刷视频点赞, 然后继续下一轮

    程序使用了递归, 如果运行时间过长, 内存占用会变大. 有什么方法可以优化这一点?

    我尝试过使用 whilecontinue:

    while (true) {
      if (condition1) {
        doSometing2();
        continue;
      }
      if (condition2) {
        doSometing2();
        continue;
      }
      ..
    }
    

    死循环会让外面的 setInterval 不被执行.

    还尝试过使用 generator 来做, 配合 redux-saga, 但这个框架不支持 es6, 在使用 babel 转译时候, 遇到一堆问题, 就跑不通了.

    所以除了 以上几种方法, 还有什么方法可以优化吗?

    15 条回复    2021-12-20 14:00:28 +08:00
    MegrezZhu
        1
    MegrezZhu  
       2021-12-19 18:28:42 +08:00
    我想了很多,写了一点伪代码,然后删掉了。
    为什么不直接五分钟重启一次脚本呢[狗头]
    ch2
        2
    ch2  
       2021-12-19 18:29:50 +08:00
    看了一下,你应该使用定时任务而不是递归来完成你想要的操作
    加一个全局变量 working ,start 开始的时候设置 working 为 true ,结束的时候设置为 false
    然后定时每隔 10 秒触发一次 start ,如果正在 working 直接 return
    再把 start 函数里把递归调用自己的全部注释掉
    lscho
        3
    lscho  
       2021-12-19 18:34:09 +08:00
    递归引起的堆栈溢出改成尾递归或者匿名函数都可以解决。但是你的代码里最明显的是 setInterval 问题,setInterval 长时间运行会内存增大不是常识吗?先把这个解决了再看是不是递归的问题吧。
    FaiChou
        4
    FaiChou  
    OP
       2021-12-19 18:54:13 +08:00
    @MegrezZhu 额, 上面只是个 demo, 实际代码比这复杂的多, 要抢红包 /抢东西, 需要每 300 毫秒截图判断, 重启脚本这代价太大了.


    @ch2 哦. 知道了, 我太愚蠢了. 可以直接 setInterval(start, 500) 来做无限循环. 本来没想用这方法是考虑到有这情形:

    function start() {
    ...
    if(cond) callA();
    ...
    }

    function callA() {
    var someVars = ...;
    doMainTask();
    setTimeout(function() {
    // 10 秒钟没干完,直接退出
    closureUseVar(someVars);
    cancelMainTask();
    exitPage();
    start(); // here 又递归了
    }, 10000)
    }

    (v2ex 回复会把代码缩进吃掉)

    这样, 按你的方法, 加一个 flag 控制, 使用 setInterval 来进行无限循环就可以了. 在使用到递归的地方 直接设置 `flag = !flag`;
    FaiChou
        5
    FaiChou  
    OP
       2021-12-19 19:02:03 +08:00
    @lscho setInterval 长时间运行为啥会增大内存? 我没考虑到这个问题. interval 结束函数都被 GC 了吧 ?
    FaiChou
        6
    FaiChou  
    OP
       2021-12-19 19:09:17 +08:00
    @lscho 确实搜到 setInterval 在浏览器下, 如果浏览器 tab 不是激活状态, 会有积压的问题, 导致一下子执行很多函数, 浏览器卡死. https://www.v2ex.com/t/761311
    FaiChou
        7
    FaiChou  
    OP
       2021-12-19 19:11:17 +08:00
    @lscho 那用 setTimeout 来代替:
    setTimeout(function repeat() {
    func();
    setTimeout(repeat, 9000);
    }, 9000);
    rpman
        8
    rpman  
       2021-12-19 22:53:09 +08:00
    Looping 的话应该 sleep 一下吧
    或者可以写成 Event driven
    FaiChou
        9
    FaiChou  
    OP
       2021-12-19 23:11:01 +08:00
    @rpman 嗯. 是的 就是 sleep 的, 要不然 cpu 受不了.
    2i2Re2PLMaDnghL
        10
    2i2Re2PLMaDnghL  
       2021-12-20 09:47:37 +08:00
    @lscho 尾调用优化目前只有 safari 或者用 babel 支持吧
    lscho
        11
    lscho  
       2021-12-20 10:44:51 +08:00
    @2i2Re2PLMaDnghL babel 只是把浏览器不支持的语法转为支持的,既然他能转,那就能写出来啊
    2i2Re2PLMaDnghL
        12
    2i2Re2PLMaDnghL  
       2021-12-20 11:17:17 +08:00
    @lscho 哦你是说手写 TCO 啊
    其实 OP 主题里的 start 把后续 if 全转 else if 并把 start() 换成 return start() 的话,所有 start() 就都在尾位置上了,我以为你是指这个……
    iPhone12
        13
    iPhone12  
       2021-12-20 12:40:38 +08:00 via iPhone
    1 中可以将 sleep 去掉,最后再 setTimeout(start, 0 或者 500),不会爆栈也不会阻塞后面的 setInterval
    Fatpandac
        14
    Fatpandac  
       2021-12-20 13:53:10 +08:00
    ```
    // 在首页了, 有“喜欢按钮”
    if (screen.find(LIKE_BUTTON) {
    ```
    发现 bug ,少了个右括号:joy:
    FaiChou
        15
    FaiChou  
    OP
       2021-12-20 14:00:28 +08:00
    @Fatpandac 哦.. 我都是手打的 没太注意括号, 习惯了编辑器自动补全.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1029 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:33 · PVG 03:33 · LAX 12:33 · JFK 15:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.