javascript - using promises with timeout -


in context of chrome extension, have click links cause dynamic menus built before revealing page user.

i have click each link twice, once show , once hide. hide click has occur in timeout other script can take on , build menu.

there several of these menus clicked, have created do_menu(find,clicks,cb) function find , clicks jquery selectors , cb callback.

from client end, looks like:

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!)}            );} ); 

at point deciding put these selectors collection , iterate on them, calling done function. purposes of discussion, lets wanted implement promises here.

the snag hitting don't know go in timeout. here original function.

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 built, continue         cb&&cb();     } } 

when try turn function returns promise, stuck.

do_menu_p:function(find,clicks){    var that=this;    return new promise(function(res,rej){ //  f1!        if($find).length===0){ // need build            $(clicks).click(); // show            settimeout(function(){ //         f2!                $(clicks).click(); // hide                res({status:'did it'}); // not work cuz f1!==f2 ??            });        }    }.bind(that)); } 

and client like:

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

no, can tell isn't right. yes, suck @ promises.

i find approach of checking if done, only once after 100ms bad practice. least check repeatedly. like:

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 error, avoid infinite checking.                 }             },100);         }else{ // menu built, continue             cb && cb();         }     }     check(ctr); } 

the same thing promises

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 built"));                     }                 },100);             }else{ // menu built, continue                 res({status:'did it'});             }         }         check(ctr);     }); } 

usage can be:

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); 

long story short, basically, then takes 2 functions attributes, (successcallback, errorcallback) of said promise. , can chain promises returning new promise @ end of each promise.

edit:

a simple fiddle demo

not sure if below method right way it, can give try...

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 built"));                         }                     },100);                 }else{ // menu 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); } 

Comments