zoukankan      html  css  js  c++  java
  • 一点对Promise的理解与总结

    全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/10959411.html,多谢,=。=~ 

    axios用多了就开始疑惑它里面到底是个啥,虽然总被告知它就是基于ajax的封装,但掐指一算,事情应该没这么简单,于是开始深挖,挖着挖着就挖到了Promise。毕竟axios的官方描述是这样的:Promise based HTTP client for browser and node.js。而axios其中一个特点就是Supports the Promise API,以前只知道promise是一种替代层层回调的解决方案,但现在看来我认为很有必要详细的研究一下。

    背景

    在JavaScript的世界中,所有代码都是单线程执行的。该特性导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行(否则容易发生阻塞)。异步执行可以用回调函数实现,该方式会在将来的某个时间点触发一个函数调用(回调)。但异步执行中的回调并不利于代码复用,例如:

    request.onreadystatechange = function () {
        if (request.readyState === 4) {
            if (request.status === 200) {
                return success(request.responseText);
            } else {
                return fail(request.status);
            }
        }
    }

    但如果是这样的链式写法就会好很多(先统一执行AJAX逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调用success函数或fail函数):

    var ajax = ajaxGet('http://...');
    ajax.ifSuccess(success)
        .ifFail(fail);

    什么是Promise?

    上述“承诺将来会执行”的对象在JavaScript中称为Promise对象,它有各种开源实现,但后面ES6将其写进了语言标准,统一了用法,原生提供了Promise对象,由浏览器直接支持。

    Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。

    Promise是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

    ES6规定,Promise对象是一个构造函数,用来生成Promise实例:

    var promise = new Promise(function(resolve, reject) {
      // ... some code
    
      if (/* 异步操作成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    });

    resolve:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

    reject:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去;

    Promise实例生成以后,可以用then方法、catch方法分别指定Resolved状态和Rejected状态的回调函数:

    // Promise测试(then、catch)
    new Promise(function(resolve,reject) {
        let num = Math.random() * 2;
        console.log("产生的随机数为:" + num);
        setTimeout(function () {
            if(num < 1) {
                console.log("即将执行成功");
                resolve("200 OK");
            } else {
                console.log("即将执行失败");
                reject("失败的原因是num为:" + num);
            }
        }, num * 1000);
    }).then(function(r) {
        console.log("then:" + r);
    }).catch(function(j) {
        console.log("catch:" + j);
    });

    PS:只用then也可以代替上述效果,因为then可以接受两个回调函数作为参数,第二个参数可选。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Rejected时调用:

    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    });

    链式多任务串行

    有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码,而使用Promise则可以采用链式写法:job1.then(job2).then(job3).catch(handleError)

    // Promise测试(多任务串行执行)
    var p = new Promise(function (resolve, reject) {
        console.log("resolve开始");
        resolve(8);
    });
    
    function multi(param) {
        return new Promise(function(resolve, reject) {
            console.log("计算" + param + "*" + param + ":");
            setTimeout(resolve, 1500, param * param);
        });
    };
    
    function add(param) {
        return new Promise(function(resolve, reject) {
            console.log("计算" + param + "+" + param + ":");
            setTimeout(resolve, 1500, param + param);
        });
    };
    
    p.then(multi).then(add).then(multi).then(function(param){
        console.log("得到最终的值为:" + param);
    });

    Promise.all()实现多任务并行

    一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是需要并行执行的,用Promise.all()实现如下:

    var p1 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 500, 'P1');
    });
    var p2 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 600, 'P2');
    });
    // 同时执行p1和p2,并在它们都完成后执行then:
    Promise.all([p1, p2]).then(function (results) {
        console.log(results); // 获得一个Array: ['P1', 'P2']
    });

    Promise.race()实现多任务赛跑

    有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可,其他任务的结果会被丢弃。这种情况下,用Promise.race()实现:

    var p1 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 500, 'P1');
    });
    var p2 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 600, 'P2');
    });
    Promise.race([p1, p2]).then(function (result) {
        console.log(result); // 'P1'
    });

    参考资料

    Promise:https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544

    ECMAScript 6 Promise对象:https://www.w3cschool.cn/ecmascript/3uge1q5v.html

  • 相关阅读:
    MySQL基础之 排序与限制,聚合
    AWS服务学习
    SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-006-定义切面使用xml
    SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-005-定义切面使用@Aspect、@EnableAspectJAutoProxy、<aop:aspectj-autoproxy>
    SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-004-使用AspectJ’s pointcut expression language定义Pointcut
    SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-003-Spring对AOP支持情况的介绍
    SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-002-AOP术语解析
    SPRING IN ACTION 第4版笔记-第四章Aspect-oriented Spring-001-什么是AOP
    SPRING IN ACTION 第4版笔记-第三章ADVANCING WIRING-009-用SPEL给bean运行时注入依赖值
    SPRING IN ACTION 第4版笔记-第三章ADVANCING WIRING-008-SpEL介绍
  • 原文地址:https://www.cnblogs.com/dreamsqin/p/10959411.html
Copyright © 2011-2022 走看看