手把手带你了解:javascript中Promise,async和await的使用

Hello,大家好,今天跟大家聊一下javascript中的Promise,以及aync和await关键字。

本篇文章分为三个模块来讲:1、同步和异步;2、Promise;3、async和await。

1、同步和异步

同步这个名字,起的并不是很好,会让人产生歧义。准确来说,应该是“按照顺序”。

func1();

func2();

func3();

func1执行完了, 执行func2func2执行完了,执行func3。这就是同步。

那什么是异步呢?异步就是大家各做各的,互不干扰,无需互相等待。

但请注意,各做各的,并不意味着乱序。它们依然是按照顺序执行的。只不过,func1还没执行完,func2就已经可以执行了。

那么JavaScript里面有哪些异步函数呢?settimeout函数、fetch函数,这些都是异步函数。

2、Promise

Promise中文意思是承诺,在JavaScript里面,你可以通俗地理解为:把这个任务(函数)交给我吧,我来完成。

2.1 Promise是怎么用的

接下来,讲讲Promise是怎么用的。Promise,它是一个类,实例化之后,会生成一个对象。

在下面这个例子中,我创建了p1,这样一个Promise对象。构造函数传入一个haha函数,haha函数里面又有两个参数,tmp1tmp2

tmp1tmp2,这俩又分别是两个函数。

(这里会比较绕,没办法,这个语法它就这样,我也很无奈。)

const num = 1;

const p1 = new Promise(function haha(tmp1, tmp2) {
    if (num == 1) {
        tmp1("haha nice! ");
    } else {
        tmp2("hehe error!");
    }
});

p1.then(function f123(params) {
    console.log(params);
})

p1.catch(function f123(params) {
    console.log(params);
});

tmp1tmp2这两个函数,又可以传参进去。这里我传入了字符串。

当然,也可以传其它的东西进去,例如:传一个对象{num:1},一个数组[1,2,3,4]等等。

这样一来,Promise这个对象就实例化完成了。

请一定要注意:你的promise对象实例化完成之后,haha函数就已经开始执行了。

实例化完成之后,你可以调用then函数,将传入tmp1函数的那个值取出来。
then函数传进去一个函数f123,将传给tmp1的那个字符串取出来。

(这里会比较绕,请对照代码仔细品味。没办法,这个语法它就这样,我也很无奈。)

另外,当你使用catch函数的时候,可以把tmp2传入的对象,取出来使用。

我这里的命名都是比较通俗的,目的是希望大家能看出来,这只是一些自定义的普通函数而已。

好了,完成了。

上面这个demo,异步的效果还不是很明显,我们再来看一个异步效果明显的场景。

我构造了一个Promise象,叫做p2

为了演示方便。这里,我只使用了tmp1,没有使用tmp2。放心,这样也是可以的。

我在haha这个函数里面,写入了一个settimeout异步函数,这个异步函数,我让它等待三秒之后,执行funcTmp

//异步的场景
const p2 = new Promise(function haha(tmp1, tmp2) {
    setTimeout(function funcTmp() {
        tmp1('nice SetTime OKOK!!');
    }, 3000);
});

p2.then(function thenfunc(tmp) {
        console.log(tmp);
    });

console.log('test demo');

到此,p2这个Promise对象就搞定了。请一定注意:这个对象生成之后,异步函数settimeout就开始计时了。

接下来,我调用了p2.then这个函数。将传入tmp1函数的那个字符串取出来。

执行这段代码,你会看到,“test demo”这个字符串是后执行的,却先打印;过了三秒之后,“nice SetTime OKOK!!”这个字符串才打印出来。

2.2 为什么要用Promise

有编程基础的朋友,可能会好奇。上面那个场景,我直接用settimeout函数等待3秒,不就行了吗?为啥还把它放进Promise对象里面?这不是多此一举吗?

没错,针对这个简单场景,确实是有点多此一举了。但是,想象这样的一个场景:我想延迟3秒之后打印"demo 333" ,再延迟2秒之后打印“demo 222!”。

这个代码你要怎么写?

如果没有Promise,大概率你会这样写:settimeout里面嵌套一个settimeout

setTimeout(function () {
    console.log('demo 333!');

    setTimeout(function () {
        console.log('demo 222!');
    }, 2000);

}, 3000);

那如果这个场景再复杂一点呢?我想在输出“demo 222!”之后,再间隔4秒输出另外一个字符串。这要怎么写?那就又要嵌套一层,settimeout函数了。

要按这种方法写下去,子子孙孙无穷尽也。代码的阅读性可就太差了。

如果我们用Promise进行编码,情况就不一样了。

我先实例化一个Promise对象p1,让它间隔3秒之后,打印“demo 333!”。

之后,调用p1then函数,将tmp1的结果取出。然后,在p1then函数里,实例化一个新的对象p2

p2给它一个新的settimeout函数,让它间隔2秒之后,打印“demo 222!”。

接着,我再调用p2then函数,将结果取回。

//用Promise来改写

const p1 = new Promise(function haha(tmp1, tmp2) {
    setTimeout(function () {
        tmp1('demo 333!');
    }, 3000);
});

let p2 = p1.then(function thenfunc1(tmp) {
    console.log(tmp);
    
    const p2 = new Promise(function haha(tmp1, tmp2) {
        setTimeout(function () {
            tmp1('demo 222!');
        }, 2000);
    });
    
    return p2;
})

p2.then(function thenfunc2(tmp) {
    console.log(tmp);
});

console.log('test demo');//用来验证异步效果

有没有感觉它的逻辑更清晰了呢?

我承认,它的代码量的确比前一种方法,更多了一些。但不得不说,它的结构更清晰,阅读更加友好。

细细品味一下吧,或者,把代码copy下来,自己执行一下,按照你的想法改动一些地方,看看是否符合你的预期,这会加深你对Promise的理解。

如果你还是觉得很麻烦,不要紧,asyncawait关键字能解决你的痛苦。

3、async和await

Promise的出现确实解决了多个异步函数嵌套的那种繁琐场景。但是,我承认,Promise用起来确实也没那么简洁。

接下来介绍一下asyncawait,它们是专门用来解决这个问题的。

asyncawait两个关键字是配套使用的。async,中文是异步的意思,用来修饰函数。await可以理解为”等待“,专门用来修饰Promise对象的。但一定要注意:await必须要放在async修饰的函数里使用。

举个例子:

// async 和 await
async function func1() {
    const p1 = new Promise(function haha(tmp1, tmp2) {
        setTimeout(function () {
            tmp1({ num: 1 });
        }, 3000);
    });

    let obj = await p1;
    console.log(obj);
}

func1();

console.log('test Demo');//用来验证异步

我用async修饰了func1函数,await修饰了Promise实例化后的对象p1;然后,声明了一个变量obj,用它来接受tmp1函数的传参对象{num:1}。

func1函数搞定之后,在外部调用一下,就可以看到它的异步效果了。

如果我们用asyncawait来改写上面那个场景,那就更加清晰、简单了。

我们先定义一个异步函数func2,它用async关键字修饰。

func2函数里面,先实例化一个Promise对象p1。请一定要注意:当实例化p1完成之后,计时就已经开始了。

然后,用await关键字修饰p1,因为有await关键字的修饰,程序会等待p1的结果,也就是“demo 333!”结果的返回。

接着,我们再实例化另外一个Promise对象p2,然后,再用同样的方法await,获取p2的结果“demo 222!”。

最后,我调用了func2函数,来执行它。就会得到跟之前一样的效果。

async function func2() {
    const p1 = new Promise(function haha(tmp1, tmp2) {
        setTimeout(function () {
            tmp1('demo 333!');
        }, 3000);
    });

    let str = await p1;
    console.log(str);

    const p2 = new Promise(function haha(tmp1, tmp2) {
        setTimeout(function () {
            tmp1('demo 222!');
        }, 2000);
    });

    str = await p2;
    console.log(str);
}

func2();

console.log('test Demo');//测试异步效果

这种写法是不是更加简便、清晰呢?

以上就是关于同步异步、Promise以及async、await的技术分享,感谢阅读。这部分知识会有点绕,光看文章是无法理解的,你需要把代码copy下来,在浏览器上运行一下,才能彻底理解它的用法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值