V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lolizeppelin
V2EX  ›  程序员

Promise 中如何 sleep(不是实现 sleep)

  •  
  •   lolizeppelin · 2018-06-27 11:46:55 +08:00 · 3856 次点击
    这是一个创建于 2102 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我的函数原型如下

    
    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
    
    
    class GversionsBulkUpdate extends React.Component {
    
      ......
    
      update = async () => {
        const { handleLoadingClose, handleLoading, appStore } = this.props;
        handleLoading();
    
        let bulkMax = 10;   // 最大并发值
        const fails = [];
    
        await new Promise((resolve) => {
          const isFinish = finish(this.state.list.length, resolve);                  // finish mark
          this.state.list.forEach((pkginfo) => {
            while (bulkMax <= 0) await sleep(300); // 限制并发数量
            bulkMax -= 1;
            const body = { address: pkginfo.url, gversion: pkginfo.gversion, ftype: pkginfo.ftype };
            goGameRequest.createPfile(appStore.user, pkginfo.pkg.package_id, body,
              () => { console.log('finish one'); bulkMax += 1; isFinish.next(); },  // error callback
              (msg) => {                                                            // success callback
                console.log(msg);
                bulkMax += 1;
                isFinish.next();
                fails.push({ pkg: pkginfo.pkg, msg });
              });
          });
        });
        console.log(fails)
        const msg = fails.length === 0 ? '批量更新执行完毕' : '部分包更新失败';
        handleLoadingClose(msg);
        this.setState({ parameters: Object.assign({}, BaseParameters),
          list: Object.assign([], baseList),
          packages: Object.assign([], this.pacakges) });
      };
      
      ......
    

    createPfile 是个 http 请求

    想用 while (bulkMax <= 0) await sleep(300); 限制并发请求数量

    但是语法错误....Promise 中需要等待要如何写..有点懵比了

    20 条回复    2018-06-28 01:08:34 +08:00
    sethverlo
        1
    sethverlo  
       2018-06-27 11:48:03 +08:00
    coderfox
        2
    coderfox  
       2018-06-27 11:55:38 +08:00 via Android
    删掉 await new Promise 的包装。
    因为 new Promise 那里接受一个闭包参数,闭包函数不是 async,所以不能在其中使用 await。
    没有必要在 async 函数中还手动构造 Promise 然后 await 掉。
    建议重新学学 Promise。
    lolizeppelin
        3
    lolizeppelin  
    OP
       2018-06-27 11:57:07 +08:00
    await new Promise 是为了等待这个 Promise 结束以后才调用 handleLoadingClose, 故意那样写的谢谢
    lolizeppelin
        4
    lolizeppelin  
    OP
       2018-06-27 11:58:44 +08:00
    hahastudio
        5
    hahastudio  
       2018-06-27 11:58:59 +08:00
    https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep
    function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
    }
    hahastudio
        6
    hahastudio  
       2018-06-27 12:01:17 +08:00
    主要是不是丢给 promise 的函数没有 async 啊
    orzfly
        7
    orzfly  
       2018-06-27 12:01:27 +08:00 via Android
    唉,你的 forEach 后的函数没有带 async 修饰字,而且 forEach 也不支持 Promise,所以不能用 await。你可以用原生的 for 循环代替 forEach,或者用 Bluebird.map 等函数代替 forEach。
    orzfly
        8
    orzfly  
       2018-06-27 12:02:42 +08:00 via Android
    所以,限制并发的话,也可以试试 Bluebird.map(..., ..., { concurrency: 5 })。
    lolizeppelin
        9
    lolizeppelin  
    OP
       2018-06-27 12:04:24 +08:00
    @sethverlo
    谢谢...但这个也不好用 我想要能阻塞住 this.state.list.forEach((pkginfo)

    delay 的实现不了啊.....

    如果不行的话我只能写个大循环, 每次先先判断是否到并发上限....到上限就延迟...没到上限就扫描 this.state.list

    每次还要把已经完成的从 this.state.list 移出去....写起来忒难看
    lolizeppelin
        10
    lolizeppelin  
    OP
       2018-06-27 12:11:29 +08:00
    @orzfly

    可以了....谢谢你的提醒 要的就是这个效果

    this.state.list.forEach(async (pkginfo)

    就可以了!!!! 3q
    lovedebug
        11
    lovedebug  
       2018-06-27 12:17:31 +08:00
    this.state.list.forEach 最好换成 await Promise.all(this.state.list.map(async (pkginfo) =>{})
    既然你限制并发数,还用 forEach,每次取 10 个做不好吗?多余的 return,等待达成进入条件
    lolizeppelin
        12
    lolizeppelin  
    OP
       2018-06-27 12:29:02 +08:00
    @lovedebug

    不能等 10 个完成...再下一批 10 个....

    要做到完成一个 下一个立刻上....

    用 sleep 已经算偷懒写法了..... 正确的写法应该是完成的直接 yeid 过去...js 我没那么熟悉 sleep 解决就算了
    lovedebug
        13
    lovedebug  
       2018-06-27 13:11:14 +08:00
    考虑 node 的库吧。或者自己内部写个定时器。周期性检测是否可以执行。
    lovedebug
        14
    lovedebug  
       2018-06-27 13:13:46 +08:00
    如果单纯要连续做任务,换成队列不断的取就可以。类似 Java 线程池。
    momocraft
        15
    momocraft  
       2018-06-27 13:49:53 +08:00
    你需要 delay 的其实是开始而不是结束,Promise 对象生成时那个任务已经开始了,再想想吧。
    famiko
        16
    famiko  
       2018-06-27 13:52:59 +08:00
    限制并发。。Promise.race 了解一下
    jimliang
        17
    jimliang  
       2018-06-27 14:08:53 +08:00
    bluebird 的 Promise 支持修改并发数
    http://bluebirdjs.com/docs/api/promise.map.html
    ```
    ...map(..., {concurrency: 3});
    ```
    lolizeppelin
        18
    lolizeppelin  
    OP
       2018-06-27 14:18:01 +08:00
    @momocraft
    并不是 delay 完就能执行啊.....delay 完我还要判断是否达到上限,还是在上限还得 delay 啊.....

    @jimliang
    谢谢提供新的解决方法....不过这边已经解决了就不引入更多的库了
    jimliang
        19
    jimliang  
       2018-06-27 20:48:57 +08:00
    @lolizeppelin 不一定要引库,只是作为参考自己写一个并发控制的逻辑
    wangjie
        20
    wangjie  
       2018-06-28 01:08:34 +08:00 via Android
    @lolizeppelin #3 2l 就指出了你的语法错误所在你还没有意识到 XD
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2783 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 12:51 · PVG 20:51 · LAX 05:51 · JFK 08:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.