• “渣男”之Promise


    "渣男"之Promise

    一.为"渣男"正名

      在之前写过一篇《NodeJS回调地狱》的文章,文章最后提到过使用Promise和async来解决"回调地狱"的问题,本文主要讲解Promise。如标题所示,我为什么把Promise叫做 "渣男"呢,从字面意思来看,Promise是承诺的意思,就是现在我给不了你结果,但是在未来我会给你一个结果,听起来就像一个渣男的言辞,这只是笔者打了个比方而已,请各位读者不要往心里去。那么我们言归正传,正是因为Promise的这种行为方式,就可以很好的解决回调地狱的问题,听起来可能有点懵,当你看完全文可能就不会有这种感觉了。

    二.Promise状态机

      Promise除了是个"渣男"外,它还是一个状态机,总共有三种状态: pending、resolved、rejected。pending是待决状态,说白了就是Promise还未给出任何的结果,即 "渣男"还在犹豫;resolved就是给出正确的结果,"渣男"给出一个好的结果,那么他就不是一个"渣男";rejected就是给出错误的结果,那么他就是一个名副其实的 "渣男"。我们通过代码来解释一下这三种状态

    function promTest() {
        /**
         * Promise的构造方法接收一个方法,方法有两个参数,第一个参数
         * 用于返回正确的结果;第二个参数用于返回错误的结果;两个参数均为方法
    * 只能接收一个参数
    */ return new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 200) }) } let promise = promTest() //此时promTest中的Promise并没有给出结果, 此时的状态为pending console.log(promise) /** * promTest中过了200ms, Promise才给出结果, 这里过 * 300ms再次打印promise, 此时promise的状态为resolved */ setTimeout(() => { console.log(promise) }, 300)

      在chrome控制台中执行的结果如下图:

                                                                                          

       接下来将代码promTest方法中的resolve('success')改为 reject(‘’fail),那么在chrome控制台的输出入下:              

                                                                                         

    三.Promise异步编程

      对Promise的执行then或者catch操作会返回一个新的Promise,该Promise最终状态根据then和catch的回调函数的执行结果决定,遵循着以下三个原则:

        A.如果回调函数最终是throw,该Promise是rejected状态

            B.如果回调函数最终是return,该Promise是resolved状态

            C.如果回调函数最终retuen一个Promise,该Promise会和回调函数return的Promise状态保持一致

      接下来,我们对三个原则分别展开阐述

    3.1.回调函数throw

    function promTest() {
        /**
         * Promise的构造方法接收一个方法,方法有两个参数,第一个参数
         * 用于返回正确的结果;第二个参数用于返回错误的结果
         */
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('success')
            }, 200)
        })
    }
    
    let promise = promTest()
    
    //因为promise必然进入then方法,那么在该回调函数中
    //抛出异常,promise2也是一个Promise,状态为rejected
    let promise2 = promise 
                .then(res => {
                    //抛出异常
                    throw new Error('fail')
                })
    
    // promise和promise2的状态均为pending
    console.log(promise)
    console.log(promise2);
    
    setTimeout(() => {
        console.log(promise)
    // promise2的状态得根据promse回调函数then来决定,而在then中直接抛出异常
    console.log(promise2)
    }, 300)

      chrome的执行结果如下:

                                                                                    

    3.2.回调函数return

    function promTest() {
        /**
         * Promise的构造方法接收一个方法,方法有两个参数,第一个参数
         * 用于返回正确的结果;第二个参数用于返回错误的结果
         */
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('fail')
            }, 200)
        })
    }
    
    let promise = promTest()
    
    //因为promise必然进入catch方法,但是在catch回调
    //函数中直接return一个值,promise2的状态为resolved
    let promise2 = promise 
                .catch(error => {
                    return 'fail' 
                })
    
    // promise和promise2的状态均为pending
    console.log(promise)
    console.log(promise2);
    
    setTimeout(() => {
        console.log(promise)
        console.log(promise2)
    }, 300)

      chrome的执行结果如下:

                                                                                    

    3.3.回调函数return一个Promise

    function promTest() {
        /**
         * Promise的构造方法接收一个方法,方法有两个参数,第一个参数
         * 用于返回正确的结果;第二个参数用于返回错误的结果
         */
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('success')
            }, 200)
        })
    }
    
    let promise = promTest()
    
    // 因为promise必然进入then方法,但是在then回调
    // 函数中直接return一个Promise,promise2的状态
    // 与回调函数中的返回的Promise的状态一致
    let promise2 = promise 
                .then(res => {
                    return new Promise((resolve, reject) => {
                        reject('fail')
                    })
                })
    
    // promise和promise2的状态均为pending
    console.log(promise)
    console.log(promise2);
    
    setTimeout(() => {
        console.log(promise)
        console.log(promise2) // promise2的状态为reject
    }, 300)

      chrome的执行结果如下:

                                                                                    

    四.Promise解决回调地狱问题

      我们还是沿用《NodeJS回调地狱》中的那个面试案例来说(如果不知道那个案例的,建议点击链接过去看看),我们通过Promise来改造一下,代码如下所示:

    // 面试函数
    function interview(round) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                if(Math.random() > 0.5) {
                    resolve('success')
                }else {
                    let error = new Error('fail')
                    error.round = round
                    reject(error)
                }
            }, 200)
        })
    }
    
    interview(1)  //第一轮面试
        .then(res => {
            /**
             * interview返回一个Promise, 会得到一个新的Promise,
             * 新的Promise的状态和interview(2)的状态一致
             */
            console.log('第一轮面试通过')
            return interview(2) 
        }).then(res => {
            console.log('第二轮面试通过')
            return interview(3)
        }).then(res => {
            console.log('面试全部通过')
        }).catch(error => { 
            console.log('第 ' + error.round + ' 轮面试失败.')
        })

      chrome的执行多次的结果如下:

                                                    

    五.Promise并发执行

      现将上面的案例改一下,例如现在去两家公司面试,那么该如何处理呢?

    // 面试函数
    function interview(name) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                if(Math.random() > 0.4) {
                    resolve('success')
                }else {
                    let error = new Error('fail')
                    error.name = name
                    reject(error)
                }
            }, 200)
        })
    }
    
    Promise.all([
        interview('baidu'),
        interview('alibaba')
    ]).then(res => {
        console.log('两家公司均面试成功.')
    }).catch(error => {  //谁先reject,谁先进入该回调函数
        console.log('面试失败在 ' + error.name + ' 公司上');
    })

        执行的结果各位读者可以自行测试,我这里就不展示了。

  • 相关阅读:
    远程视频监控之应用篇(mjpg-streamer)
    C语言存储类型
    基于Qt的wifi智能小车的制作(一)
    libevent和基于libevent的网络编程
    fdisk 分区格式化为ext4格式分区
    Makefile 中:= ?= += =的区别
    【计算机网络】详解网络层(二)ARP和RARP
    Nginx 反向代理 负载均衡 虚拟主机配置
    C# 对文本文件的几种读写方法总结
    Visual Studio中Image Watch的使用
  • 原文地址:https://www.cnblogs.com/miller-zou/p/12325400.html
Copyright © 2020-2023  润新知