使用promises with timeout

时间:2015-05-08 04:46:59

标签: javascript jquery promise

在Chrome扩展程序的上下文中,我必须点击一些链接,这些链接将导致在向用户显示页面之前构建动态菜单。

我必须点击每个链接两次,一次显示,一次隐藏。隐藏点击必须在超时时发生,以便其他脚本可以接管并构建菜单。

有几个菜单要点击,所以我创建了一个do_menu(find,clicks,cb)函数,其中findclicks是jQuery选择器,cb是回调。< / p>

从客户端,这看起来像:

that.do_menu('<seek menu selector>'
            ,'<make menu on click selector>'
            ,function(){that.do_menu('<seek menu selector>'
                                    ,'<make menu on click selector>'
                                    ,function(){that.do_menu('etc'
                                                            ,'etc',ugh!)}
           );}
);

此时我决定将所有这些选择器放入一个集合并迭代它们,最终调用done函数。但就本次讨论而言,我想说我想在这里实现Promises。

我遇到的障碍是,我不知道在超时时间去哪里。这是原始功能。

do_menu:function(find,clicks,cb){
    if($(find).length===0){ // menu needs building
        $(clicks).click(); // show menu
        setTimeout(function(){
            $(clicks).click(); // hide menu
            cb&&cb();
        },100);
    }else{ // menu already built, continue
        cb&&cb();
    }
}

当我尝试将其转换为返回Promise的函数时,我会陷入困境。

do_menu_p:function(find,clicks){
   var that=this;
   return new Promise(function(res,rej){ //  F1!
       if($find).length===0){ // need to build
           $(clicks).click(); // show
           setTimeout(function(){ //         F2!
               $(clicks).click(); // hide
               res({status:'did it'}); // This will not work cuz F1!==F2 ??
           });
       }
   }.bind(that));
}

我的客户看起来像:

var that=this;
this.do_menu_p('<menu>','<click>')
.then(/*hmmm...??*/ that.do_menu_p.bind(that,'<more>','<args>'))

不,我可以说这不对。是的,我很擅长承诺。

2 个答案:

答案 0 :(得分:1)

我发现在100ms之后检查某些事情是否完成,的方法是不好的做法。你能做的最少是反复检查。类似的东西:

do_menu:function(find,clicks,cb){
    var ctr = 0;
    function check(){
        if($(find).length===0){ // menu needs building
            $(clicks).click(); // show menu
            setTimeout(function(){
                $(clicks).click(); // hide menu
                ctr++;
                if(ctr<10){
                     check();
                }else{
                    //throw some error, to avoid infinite checking.
                }
            },100);
        }else{ // menu already built, continue
            cb && cb();
        }
    }
    check(ctr);
}

与承诺相同的事情

do_menu_p:function(find,clicks){
    return new Promise(function(res,rej){
        var ctr = 0;
        function check(){
            if($(find).length===0){ // menu needs building
                $(clicks).click(); // show menu
                setTimeout(function(){
                    $(clicks).click(); // hide menu
                    ctr++;
                    if(ctr<10){
                         check();
                    }else{
                        rej(new Error("Menu cannot be built"));
                    }
                },100);
            }else{ // menu already built, continue
                res({status:'did it'});
            }
        }
        check(ctr);
    });
}

用法可以是:

var that=this;
this.do_menu_p('<menu>','<click>')
.then(function(res){
    return that.do_menu_p('<more1>','<args1>'));
}).then( function(res){
    return that.do_menu_p('<more2>','<args2>'));
}).catch( errorHandler);

长话短说,基本上,then将两个函数作为所述Promise的属性(successCallback,errorCallback)。   并且你可以通过在每个承诺结束时返回新承诺来链接承诺。

编辑:

一个简单的fiddle demo

不确定下面的方法是不是正确的方法,你可以尝试一下......

do_menu_p:function(array){

    if(!array || array.length<2) return;
    function innerPromFn(i){
        var find = array[i], clicks = array[i+1];
        return new Promise(function(res,rej){
            var ctr = 0;
            function check(){
                if($(find).length===0){ // menu needs building
                    $(clicks).click(); // show menu
                    setTimeout(function(){
                        $(clicks).click(); // hide menu
                        ctr++;
                        if(ctr<10){
                             check();
                        }else{
                            rej(new Error("Menu cannot be built"));
                        }
                    },100);
                }else{ // menu already built, continue
                    res({status:'did it'});
                }
            }
            check(ctr);
        }).then(function(res){
            i+=2;
            if(i>array.length){
                return res;
            }else{
                return innerPromFn(i);
            }
        });
    }

    return innerPromFn(0);
}

答案 1 :(得分:0)

这是我想出的。打三脚驴。检查的内容被遗漏了,我只需要能够使用超时来限制承诺。

var menus=[{id:0},{id:1},{id:2},{id:3}];

function doer(menu){
    return new Promise(function called(res,rej){
      console.log('click1:'+menu.id);
      setTimeout(function(){
        if(menu.id===2){return rej(new Error('could not'));}
        console.log('click2:'+menu.id);
        res(1);// happy
      },Math.random()*8000);
    });  
}

Promise.reduce(menus,function(ctr,cur,i){
  return doer(menus[i]).then(function(res,rej){
     console.log('happy:',res);
  });
},$.when(1)).then(function(){
  console.log('everyones done'); //no errors
}).catch(function(eee){
  console.log('Error:',eee);
}).finally(function(){
  console.log('finally');
});

如果重要的话,这是Bluebird。我不知道Bluebird相当于$.when(1)