在Chrome扩展程序的上下文中,我必须点击一些链接,这些链接将导致在向用户显示页面之前构建动态菜单。
我必须点击每个链接两次,一次显示,一次隐藏。隐藏点击必须在超时时发生,以便其他脚本可以接管并构建菜单。
有几个菜单要点击,所以我创建了一个do_menu(find,clicks,cb)
函数,其中find
和clicks
是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>'))
不,我可以说这不对。是的,我很擅长承诺。
答案 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)。
并且你可以通过在每个承诺结束时返回新承诺来链接承诺。
不确定下面的方法是不是正确的方法,你可以尝试一下......
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)
。