在不用Promise的情况下如何控制异步请求?

Posted 手撕黄油

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在不用Promise的情况下如何控制异步请求?相关的知识,希望对你有一定的参考价值。

  如何更好的控制异步请求?相信大家一定首选Promise对象。确实,使用Promise控制异步请求确实非常方便,直接使用then()方法就可以实现当一个异步请求完成后再处理另一个请求或操作。同时,这样的代码也避免了使用大量的回调函数造成的“丑陋的代码”。

  不过,在实际的工作中却总是不能尽人意。虽然es6越来越普及,但偶尔也会遇到一些维护老项目的情况,况且Promise的兼容性也是个问题......

 

恰好我今天也遇到了这个问题,不过情况更加复杂一些。简单描述一下就是——老项目有一个需求就是给一个游戏新增一个小结页,把原来老的小结页(写在iframe里)去掉。直接结果就是页面的按钮减少了,但事件数量不变,且都绑在了一个按钮上。这个按钮点击后意味着做完一道题,就要做一次异步请求来保存答案,然后判断是最后一题的话点击后会触发iframe的postMessage且切换页面,之后还有一次异步请求。由于全部是异步请求,这也直接导致了如果请求速度比较慢的话,页面先postMessage切换页面后,请求直接会shutdown掉!

 

 

所以要改的目的也很明确,就是当做到最后一题的时候,先执行完两个异步请求,最后再postMessage切换页面。老司机肯定都知道如果不能用Promise的话直接用回调函数就好了。不过这两个异步请求没有绑定在一起,所以想直接用回调函数也不是那么容易。我想了很久,实在搞不定,后来找leader,leader用一个巧妙的方法帮我搞定了。(我遇到的情况可能比较特殊,不过leader的这个思路确实非常棒)下面直接show给大家看!

 

$("#next").click(function(){ //每做完一题点击按钮保存
     saveQuestion(title); //执行保存游戏的异步操作
       
     if(....){
        //执行一些操作
    };

     if(....){
        //执行一些操作
    };
    
     if(game.over == true){ //当做到最后一题时会触发
        postMessage(title); //iframe postMessage出去并切换页面,此时saveQuestion和saveTask没有完成请求的话会被shut down;
    
        saveTask(title); //执行第二个异步请求
    }  

})       

如果按照上述代码做的话请求会被关闭掉,原因我也说了,那么此时我们该如何做才能保证两个请求执行完再执行postMessage的操作呢?

$("#next").click(function(){
    var flags = {
        done:false
    };
    savaQuestiontitle, flags); 

    if.....

    if.....

    if(game.over == true){
        var showPostMessage = postMessage.bind(undefined,title);
        var callback = function(flags,func){
              while(flags.done == false){};
              func();
        }
        callback = callback.bind(undefined,flags,postMessage); 
     saveTask(title,callback);
    }
})

只要把代码写成这样就可以成功运行了!有的朋友可能看不懂,别急,我一句一句来分析!

首先先写一个flags对象,将flags作为参数传入异步请求的函数中,这个对象的作用主要用来控制异步请求的完成。只有当saveQuestion内的请求success或error后,将flags的done属性变为true;之后便是一系列if的判断,我们暂且省略;直到游戏结束时,我们声明一个回调函数callback ,这个回调函数传入两个参数,一个是flags对象,另一个是函数(即posMessaget);callback内部先是使用一个while循环,在flags.done为false时不停的循环,什么也不做。根据前面我们知道只有在saveQusetion异步请求结束后flags.done才会为true,所以说这个回调函数是为了控制saveQuestion的;

最后,我们再将回调函数放入saveTask中作为第二个参数,只有当saveTask请求结束后才调用callback!这样一来我们就可以保证整个程序先执行saveQuestion,虽然不知道saveQuestion什么时候请求结束,但可以通过flags.done来判断;之后执行saveTask,只有执行完saveTask后才会执行回调函数;如果此时saveQuestion请求还没结束,callback会在内部使用while等待请求,只有成功后才会执行最后的postMessage!

以上是关于在不用Promise的情况下如何控制异步请求?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不返回 Promise 的情况下从对象的`get()` 获取异步数据

怎么用promise实现异步控制

ES6:何为Promise?

Promise 在这种情况下如何执行?

前端面试题之手写promise

聊一聊Promise