在 Chrome 扩展程序的上下文中,我必须单击一些链接,这将导致在向用户显示页面之前构建动态菜单。
我必须单击每个链接两次,一次显示,一次隐藏。隐藏点击必须在超时时间内发生,以便其他脚本可以接管并构建菜单。
有多个菜单可供点击,因此我创建了一个 do_menu(find,clicks,cb)
函数,其中 find
和 clicks
是 jQuery 选择器,cb
是回调。
从客户端来看,这看起来像:
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
函数。但出于本次讨论的目的,假设我想在这里实现 Promise。
我遇到的障碍是我不知道暂停时该去哪里。这是原始函数。
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>'))
不,我知道这是不对的。是的,我不相信 promise 。
最佳答案
我发现在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);
}
promise 也是如此
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)。
您可以通过在每个 promise 结束时返回新的 promise 来链接 promise 。
编辑:
一个简单的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);
}
关于javascript - 使用带超时的 Promise,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30115945/