TS Promise && async && await

发布时间:2023年12月22日

一.Promise

? ? ? ? Promise是异步编程的一种解决方案。相比于以前通过一个callback嵌套一个callback的写法(回调地狱),Promise的写法更加直观,简洁。Promise一共有三种状态:

1.pending状态,通过new创建promise对象后,就会出于pending状态。
2.resolved状态,当promise对象需要执行的函数顺利执行完成时,可以把pending状态切换成resolved状态。
3.rejected状态,当promise对象执行函数出现异常导致执行失败时,就把pending状态切换到rejected状态。

? ? ? ? 因为JavaScript是单线程的,所以需要实现像协程一样的异步操作,可以在异步函数内部通过类似setTimeout等方式让协程挂起等待,让其他协程(或者说主程序)继续运行下去,从而实现非阻塞。 下面是一段简单的伪代码,来展示创建Promise的大致全过程:

private test(){
        // new Promise: 创建promise对象
        // (resolve, reject): resolve是当函数顺利执行完后,把promise的状态从pending切换成resolved的
        // (resolve, reject): reject是当函数执行失败时,把promise的状态从pending切换成rejected的
        return new Promise((resolve, reject)=>{
            // 通过setTimeout来让协程挂起,让主程序继续执行
            setTimeout(()=>{{
                    console.log("test")

                    if(true){
                        // 程序运行成功,则把promise的状态从pending切换成resolved的
                        resolve("true")
                    }else{
                        // 程序运行失败,则把promise的状态从pending切换成rejected的
                        reject("false")
                    }
                }
    
            }, 1000)
        })
    }

? ? ? ? 通过Promise的then函数可以在异步函数运行结束时,接收处理结果,并做相关的处理操作,then函数可以接受两个callback,第一个callback,当Promise调用resolve函数时会触发,第二个callback会在Promise调用reject时触发。 伪代码如下:

start () {
        console.log("start 1")
        this.test().then(
            // 当Promise调用resolve时,会触发这个回调函数(info:接收resolve函数传的参数)
            (info)=>{
                console.log("test function success = ", info)
            }, 
            // 当Promise调用reject时,会触发这个回调函数(err:接收reject函数传的参数)
            (err)=>{
                console.log("test function fail = ", err)
            })
        console.log("start 2")
    }

? ? ? ? 上面那段代码的第二个callback其实已经接收了失败时传回来的错误信息了,但我们还有另外一种写法,Promise提供了catch的方法来捕获异常,如果你调用then时已经传入第二个callback接收异常数据,异常信息就会抛给then的第二个callback(毕竟我的代码里是先调用then再调用catch的),如果没写第二个callback也可以通过catch来捕获异常,伪代码如下:

start () {
        console.log("start 1")
        this.test().then(
            // 当Promise调用resolve时,会触发这个回调函数(info:接收resolve函数传的参数)
            (info)=>{
                console.log("test function success = ", info)
            }).catch((err)=>{
                // 通过catch来捕获rejected抛出的异常信息
                console.log("test function err = ", err)
            })
        console.log("start 2")
    }

完整的测试代码如下(我是在cocoscreator的helloworld下面写的测试用例):

const {ccclass, property} = cc._decorator;

@ccclass
export default class NewClass extends cc.Component {

    start () {
        console.log("start 1")
        this.test().then(
            // 当Promise调用resolve时,会触发这个回调函数(info:接收resolve函数传的参数)
            (info)=>{
                console.log("test function success = ", info)
            }, 
            // 当Promise调用reject时,会触发这个回调函数(err:接收reject函数传的参数)
            (err)=>{
                console.log("test function fail = ", err)
            })
        console.log("start 2")
    }
    
    private test(){
        // new Promise: 创建promise对象
        // (resolve, reject): resolve是当函数顺利执行完后,把promise的状态从pending切换成resolved的
        // (resolve, reject): reject是当函数执行失败时,把promise的状态从pending切换成rejected的
        return new Promise((resolve, reject)=>{
            // 通过setTimeout来让协程挂起,让主程序继续执行
            setTimeout(()=>{{
                    console.log("test function")

                    if(true){
                        // 程序运行成功,则把promise的状态从pending切换成resolved的
                        resolve("success")
                    }else{
                        // 程序运行失败,则把promise的状态从pending切换成rejected的
                        // reject(new Error("fail"))
                        reject("fail")
                    }
                }
    
            }, 1000)
        })
    }
}

运行后的输出结果如下:

可以看到是先输出start 2然后才输出的test function,证明test函数已经异步执行了。

promise还有一个比较常用的函数,叫 all,可以同时处理多个promise对象。先上一段测试代码,通过运行结果我们来分析这个all~

结论1:虽然arrPro数组里面promise对象顺序是test1,test2,test3,但三个Promise是单独独立执行的,哪个timeout到了就先运行哪个函数,所以先执行了test3.

结论2:test3函数内部都调用了resolve和reject两个函数,但从回调结果,只响应了resolve函数,因为promise对象的状态只能改变一次,改变成resolved后就不能变了,没有resolved变成rejected的可能,所以代码块里,先调用了resolve,再调用reject就不会有结果了。

结论3:在test3函数内,即使先调用了resolve,后续代码还是会继续执行的,不会因为调用了resolve就终止函数内部后续代码的执行(这代码也就为了测试,正常情况应该尽量把resolve放到函数完成执行完成后才调用,这样才正确)

结论4:在then里面第一个callback接受到的返回数据是一个数组,数组内数据的顺序和arrPro数组内部promise对象的顺序一致。

-----------------------------------------------------------------------------------------------------
假如把上面代码里面,test3函数内部的resolve("test3 success")注释掉

-----------------------------------------------------------------------------------------------------

结论5:当test3调用了reject后,就会立即进入到then函数了(即只要任何一个promise对象状态切换到rejected,promise.all的结果都为rejected)

结论6:虽然调用reject函数后,promise.all马上就会得到rejected的结果,但另外两个方法依然有继续执行。

假如Promise.then里面再继续返回一个promise对象的话,就可以继续通过then来处理promise的执行结果,从而形成promise的链式调用,具体例子如下:

start () {
        let p = new Promise(resolve=>{
            setTimeout(()=>{
                resolve("success 1")
            },2000)
        })

        p.then((info)=>{
            // 此处继续返回一个promise对象,形成链式调用
            return new Promise(resolve=>{
                console.log("info = ", info)
                setTimeout(()=>{
                    resolve("success 2")
                },2000)
            })
        }).then((info)=>{
            console.log("info = ", info)
        })
    }

async && await

观点1. async 表明这个函数内部有可能有异步操作,搭配await使用,如果async内部没使用await等于同步执行函数,也不会存在问题。

观点2. async函数内部如果存在await,函数内部会进行等待,等待await的结果出来后再执行后续代码片,但async函数本身不会阻塞,会马上返回一个Promise对象

观点3.因为async函数非阻塞,所以会立马返回一个Promise对象,所以如果想真正拿到async函数的返回值,可以通过.then(data=>{}) 来拿到函数返回值。

观点4.因为async返回的是一个Promise对象,所以async内部如果有报错的话,就会终止整个执行过程,并通过Promise返回报错信息,使用Promise对象的catch就能抓取错误信息了。

下面来写一个小小的测试代码:

async start () {
        console.log("start 1")
        this.test1().then((info)=>{
            console.log(info)
        })
        console.log("start 2")
    }

    private async test1(){
        console.log("test1 function 1")
        await this.test().then(
            (info)=>{
                console.log("test function success = ", info)
            })
        console.log("test1 function 2")

        return "test1 function finish"
    }
    
    private test(){
        return new Promise((resolve, reject)=>{
            setTimeout(()=>{resolve("success")}, 1000)
        })
    }

运行结果如下:

结论1:虽然start函数也使用了async,但从“start1”到“start2”是连续出现的,证明了【观点1:async只是声明函数有可能存在异步操作,如果没使用await的话,其实这段函数内部代码还是同步执行的】

结论2:“test1 function 1”和"test1 function 2"两个输出不是连续打印,可以看出来确实是因为await函数导致代码停止,等待异步函数执行完后,才继续执行后续代码,验证了【观点2:使用await能使后续代码等待异步函数执行完成后才继续执行】

结论3:从“start1”到“start2”是连续出现的,并没有等待异步函数执行,验证了【观点2:async函数本身不会阻塞,会返回一个promise对象】

结论4:"test1 function finish"最后才输出,也验证了【观点3:因为async会返回一个promise,我们可以通过promise的then函数去获取async函数的返回结果】

文章来源:https://blog.csdn.net/a42626423/article/details/135101768
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。