javascript - 使用带超时的 Promise

标签 javascript jquery promise

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

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

有多个菜单可供点击,因此我创建了一个 do_menu(find,clicks,cb) 函数,其中 findclicks 是 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/

相关文章:

javascript - javascript 中的多任务按钮

javascript - JavaScript 中的无序字典

javascript - 将图像数据设置到图像src中

javascript - 将数组中的第一项包装在标签中,并将以下项目包装在其他一些标签中

javascript - 单页应用程序和 ASP.NET MVC

node.js - Firebase 在 promise 触发之前等待加载数据库数据

javascript - Promise.all 和嵌套异步等待哪个更好?

javascript - React 功能组件中的 Prop 名称

javascript - 无效的 json 字符串化

javascript - 如何从 Controller 调用嵌套在 promise 内的函数?