zoukankan      html  css  js  c++  java
  • JavaScript异步与Promise基本用法(resolve与reject)

    Promise解决的问题
    相信每个前端都遇到过这样一个问题,当一个异步任务的执行需要依赖另一个异步任务的结果时,我们一般会将两个异步任务嵌套起来,这种情况发生一两次还可以忍,但是发生很多次之后,就形成了所谓的回调地狱,代码层层嵌套,环环相扣,很明显,逻辑稍微复杂一些,这样的程序就会变得难以维护。就比如我们昨天的那个回调地狱的例子:

    function funA(callback) {
    console.log("A");
    setTimeout(() = > {
    callback()
    }, 100)
    }
    
    function funB() {
    console.log("B")
    }
    
    function funC(callback) {
    console.log("C")
    setTimeout(() = > {
    callback()
    }, 1000)
    }
    
    function funD() {
    console.log("D")
    }
    
    function funE() {
    console.log("E")
    }
    
    function funF() {
    console.log("F")
    }
    
    funA(() = > {
    funB()
    funC(() = > {
    funD()
    })
    funE()
    })
    funF()

    对于这种情况,程序员们想了很多解决方案(比如将代码模块化),但流程控制上,还是没有避免大量的嵌套。但在ES6之后的标准里,Promise的标准化,一定程度上解决了JavaScript的流程操作问题。

    什么是Promise
    在《异步与性能》的第三章中有这么个场景来比喻 Promise:

      我走到快餐店的柜台前,点了一个起士汉堡。并交了1.47美元的现金。通过点餐和付款,我为得到一个 值(起士汉堡)制造了一个请求。我发起了一个事务。

      但是通常来说,起士汉堡不会立即到我手中。收银员交给一些东西代替我的起士汉堡:一个带有点餐排队号的收据。这个点餐号是一个“我欠你”的许诺(Promise),它保证我最终会得到我的起士汉堡。

      于是我就拿着我的收据和点餐号。我知道它代表我的 未来的起士汉堡,所以我无需再担心它——除了挨饿!

      在我等待的时候,我可以做其他的事情,比如给我的朋友发微信说,“嘿,一块儿吃午餐吗?我要吃起士汉堡”。

      我已经在用我的 未来的起士汉堡 进行推理了,即便它还没有到我手中。我的大脑可以这么做是因为它将点餐号作为起士汉堡的占位符号。这个占位符号实质上使这个值 与时间无关。它是一个 未来的值。

      最终,我听到,“113号!”。于是我愉快地拿着收据走回柜台前。我把收据递给收银员,拿回我的起士汉堡。 换句话说,一旦我的 未来的值 准备好,我就用我的许诺值换回值本身。

      但还有另外一种可能的输出。它们叫我的号,但当我去取起士汉堡时,收银员遗憾地告诉我,“对不起,看起来我们的起士汉堡卖光了。”把这种场景下顾客有多沮丧放在一边,我们可以看到 未来的值 的一个重要性质:它们既可以表示成功也可以表示失败。

      每次我点起士汉堡时,我都知道我要么最终得到一个起士汉堡,要么得到起士汉堡卖光的坏消息,并且不得不考虑中午吃点儿别的东西。

      我由等待汉堡变成了等到或者等不到,这个过程不可逆,

    上面很形象的介绍了promise,上面的等待汉堡和得到汉堡,汉堡卖光了,得不到汉堡,分别对应promise的三种状态 **pending: 进行中,既不是成功,也不是失败状态。 fulfilled: 意味着操作成功完成。 rejected: 意味着操作失败。**
    Promise的基本用法
    语法

    new Promise( function(resolve, reject) {...} ); //reject参数 可不选

    参数
    executor

    executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回新建对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成fulfilled,或者在发生错误时将它的状态改为rejected。
    如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

    对更多对Promise的描述感兴趣的可以 点击查看MDN Promise下面我们开始上代码

    新建一个Promise的实例:

    let promise = new Promise((resolve, reject) = > {
    setTimeout(() = > {
    let random = Math.random()
    if (random > 0.5) {
    resolve(`resolve$ {random}`)
    } else {
    resolve(`reject$ {random}`)
    }
    }, 1000)
    })

    由上所示,Promise的构造函数接收一个函数作为参数,该函数接受两个额外的函数,resolve和reject,这两个函数分别代表将当前Promise置为fulfilled(已成功)和rejected(已失败)两个状态。Promise正是通过这两个状态来控制异步操作的结果。接下来我们将讨论Promise的用法,实际上Promise上的实例promise是一个对象,不是一个函数。在声明的时候,Promise传递的参数函数会立即执行,因此Promise使用的正确姿势是在其外层再包裹一层函数。

    let run = function() {
    return new Promise((resolve, reject) => {
    setTimeout(() => {
    let random = Math.random()
    if (random > 0.5) {
    resolve(`resolve:${random}`)
    } else {
    reject(`reject:${random}`)
    }
    }, 1000)
    })
    }
    
    run()

    这是Promise的正常用法,接下来,就是对异步操作结果的处理,接着上面创建的函数run()

    run().then(
    function(value) {
    console.log(value)
    })


    每个Promise的实例对象,都有一个then的方法,这个方法就是用来处理之前各种异步逻辑的结果。

    then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
    下面是一个用Promise对象实现的 Ajax 操作的例子:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>JavaScript异步</title>
    </head>
    <body>
    <script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script>
    <script>
    new Promise((resolve, reject) => {
    $.ajax({
    url: "https://easy-mock.com/mock/5c249dbe46e8386d0b21b475/example_copy_copy/promisetest",
    success: res => {
    if (res.code == 0) {
    resolve(res.data)
    } else {
    reject(res.desc)
    }
    }
    });
    })
    .then(res => {
    console.log(res);
    },err =>{
    console.log(err)
    })
    
    </script>
    
    </body>
    </html>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>JavaScript异步</title>
    </head>
    <body>
    <script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script>
    <script>
        var a = new Promise(
            //下面函数为executor函数,带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回新建对象前被调用)。
            (resolve, reject) => {
            $.ajax({
                url: "https://api.apiopen.top/musicBroadcasting",
                success: res => {
                    if (res.code == 200) {
                        console.log('1',res.result)
                        // resolve()异步回调将promise变为fulfilled(已成功)状态
                        resolve(res.result)//res.message为参数A
                    } else {
                        // reject()异步回调将promise变为rejected(已失败)状态
                        reject(res.result)//res.desc为参数B
                    }
                }
            });
        })
        // 每个Promise的实例对象,都有一个then的方法,这个方法就是用来处理之前各种异步逻辑的结果(fulfilled(已成功)状态或者rejected(已失败)状态)
        // 第一个回调函数是Promise对象的状态变为resolved时调用,
        // 第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
        .then(res => { 
            console.log('res参数来自resolve(A)传入的参数A',res)
        },err =>{
            console.log('reject(B)传入的参数B',err)
        })
        console.log(a)
            
    // 如果异步操作获得了我们想要的结果,那我们将调用resolve函数,在then的第一个作为参数的匿名函数中可以获取数据,如果我们得到了错误的结果,调用reject函数,
    // 在then函数的第二个作为参数的匿名函数中获取错误处理数据。
    </script>
    
    </body>
    </html>
    

      


    当res.code == 0 为接口调用成功 输出:

    手动把 上面代码 res.code == 0 改为 res.code == 1 就会抱一个错误,输出:

    如果异步操作获得了我们想要的结果,那我们将调用resolve函数,在then的第一个作为参数的匿名函数中可以获取数据,如果我们得到了错误的结果,调用reject函数,在then函数的第二个作为参数的匿名函数中获取错误处理数据。
    这样,一个次完整的Promise调用就结束了。对于Promise的then()方法,then总是会返回一个Promise实例,因此你可以一直调用then,形如run().then().then().then().then().then()…
    在一个then()方法调用异步处理成功的状态时,你既可以return一个确定的“值”,也可以再次返回一个Promise实例,当返回的是一个确切的值的时候,then会将这个确切的值传入一个默认的Promise实例,并且这个Promise实例会立即置为fulfilled状态,以供接下来的then方法里使用。看代码:

    let num = 0
    let run = function() {
    return new Promise(resolve => {
    resolve(`${num}`)})
    }
    
    run().then(val => {
    console.log(val)
    return val
    })
    .then(val =>{
    val++
    console.log(val)
    return val
    })
    .then(val =>{
    val++
    console.log(val)
    })

    输出:

    根据这个特性,我们就可以将相互依赖的多个异步逻辑,进行比较顺序的管理了,解决了让人头痛的回调地狱问题。

    今天我们就先到这里,明天我们讲一下Promise.then()与Promise.catch()

    友情链接:点击查看所有文章目录

    友情链接:点击查看 JavaScript异步系列文章目录

    原文链接:https://blog.csdn.net/qq_42911663/article/details/85790181

  • 相关阅读:
    【转】shell中的内建命令, 函数和外部命令
    clear out all variables without closing terminal
    linux中shell命令test用法和举例
    解决vim粘贴时格式混乱的问题
    scp的两种方式
    source 命令的用法,是在当前bash环境下执行脚本文件
    angularjs中下拉框select option默认值
    redux 及 相关插件 项目实战
    JavaScript 获取当前时间戳
    v-if v-else-if v-else
  • 原文地址:https://www.cnblogs.com/itgezhu/p/11983943.html
Copyright © 2011-2022 走看看