• 深入浅出写一个多级异步回调从基础到Promise实现的Demo


    今天一时兴起,写了一个渐进升级的异步调用demo,记录一下。

    1. 最基础的同步调用

    //需求:f2在f1之后执行,且依赖f1的返回值。如下:
    function f1(){
        var s="1";
        return s;
    }
    function f2(s){
        s+="-2";
        console.log(s);
    }
    f2(f1()); //"1-2"

    2. 引入异步回调

    //继续,如果f1是个耗时操作,业务上需要做成异步,那么就需要引入回调,如下:
    function f1(){
        var s;
        setTimeout(function(){
            s="1";
            f2(s);
        },1000);
    }
    function f2(s){
        s+="-2";
        console.log(s);
    }
    f1(); //"1-2"

    3. 回调函数名解耦

    //对上面代码,对f2做个函数名上的解耦,如下:
    function f1(callback){
        var s;
        setTimeout(function(){
            s="1";
            callback(s);
        },1000);
    }
    function f2(s){
        s+="-2";
        console.log(s);
    }
    f1(f2); //"1-2"
    
    //这样,不管以后f2的function name如何变更,我们都不需要去f1里修改对他的引用了

    4. 更多层级的异步回调

    //那么,我们继续,如果业务中引入了f3,且逐级依赖异步耗时操作f1和f2。如下:
    function f1(){
        var s;
        setTimeout(function(){
            s="1";
            f2(s);
        },1000);
    }
    function f2(s){
        setTimeout(function(){
            s+="-2";
            f3(s);
        },1000);
    }
    function f3(s){
        s+="-3";
        console.log(s);
    }
    f1(); //"1-2-3"
    //这时,该怎么对f2和f3的function name解耦,以及怎样保持一个类似f1().f2().f3()样子的清晰的调用呢?

    4.1 试着优雅一点

    //思来想去,看起来需要引入更多的传参,那搞两个callback参数吧:
    function f1(callback1,callback2){
        var s;
        setTimeout(function(){
            s="1";
            callback1(s,callback2);
        },1000);
    }
    function f2(s,callback){
        setTimeout(function(){
            s+="-2";
            callback(s);
        },1000);
    }
    function f3(s){
        s+="-3";
        console.log(s);
    }
    f1(f2,f3); //"1-2-3"
    //WTF,尼玛,这也太尼玛脏了。函数名虽然解耦了,调用也很清晰。但是一个callback2参数需要在多个function之间传递,代码可读性变差;并且f1中传入了并不需要处理的callback2,逻辑有些冗余。

    5. 观察者模式拉平回调

    重新思考下,看起来逐级依赖的函数回调,随着层级的加深,在传参和调用上都越来越吃力了。
    我们现在想办法拉平一下这些回调,用自定义事件改造下。
    专业术语上,叫观察者模式,即通过自定义事件的监听和触发,来实现函数的依赖调用(f1触发f2的调用)

    //注册自定义事件 拆解f1 f2 f3的依赖回调关系导致的代码逻辑上的嵌套(使用CustomEvent的detail属性,实现参数传递)
    document.addEventListener("f1:done",function(e){
        f2(e.detail);
    });
    document.addEventListener("f2:done",function(e){
        f3(e.detail);
    });
    
    
    function f1(){
        var s;
        setTimeout(function(){
            s="1";
            document.dispatchEvent(new CustomEvent('f1:done', {detail:s}));
        },1000);
        
    }
    function f2(s){
        setTimeout(function(){
            s+="-2";
            document.dispatchEvent(new CustomEvent('f2:done', {detail:s}));
        },1000);
    }
    function f3(s){
        s+="-3";
        console.log(s);
    }
    
    f1(); //"1-2-3"

    注:阮一峰的这篇文章里,还引入了一个订阅/发布模式,个人感觉没什么意义,核心原理还是事件注册,参考:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html

    6. Promise的实现

    上面的观察者模式,看起来比较优雅了,但是因为拉平几个有依赖关系的回调函数,就去注册一些自定义事件,还是感觉有点怪。
    并且,在调用上,只是写了一个f1(),并不能在调用上看出三个函数的依赖关系。
    ES6开始,引入了Promise概念,专门用来处理异步操作问题,参考:http://es6.ruanyifeng.com/#docs/promise

    //继续Promise方式,试着改写一下:
    
    function f1(){
        var p1=new Promise(function(resolve, reject) {
            var s;
            setTimeout(function(){
                s="1";
                resolve(s);
            },1000);
            
        });
        return p1;
    }
    function f2(s){
        var p2=new Promise(function(resolve, reject) {
            setTimeout(function(){
                s+="-2";
                resolve(s);
            },1000);
            
        });
        return p2;
    }
    function f3(s){
        s+="-3";
        console.log(s);
    }
    
    f1().then(function(s) {
        return f2(s);
    }).then(function(s) {
        f3(s);
    })
    
    //看起来,还不错哦
  • 相关阅读:
    String类的substring方法
    postman绕过登录,进行接口测试的方法
    Dubbo
    那些吊炸天的互联网名词
    版本控制工具git
    Ubunto20.04 sudo apt-get update 出现目标被重置多次!
    ubuntu环境下搭建Hadoop集群中必须需要注意的问题
    Python作业---内置数据类型
    python作业完成简单的文件操作
    python3实现计算器
  • 原文地址:https://www.cnblogs.com/youryida/p/9269933.html
Copyright © 2020-2023  润新知