Hello,大家好,今天跟大家聊一下javascript中的Promise,以及aync和await关键字。
本篇文章分为三个模块来讲:1、同步和异步;2、Promise;3、async和await。
1、同步和异步
同步这个名字,起的并不是很好,会让人产生歧义。准确来说,应该是“按照顺序”。
func1();
func2();
func3();
func1
执行完了, 执行func2
,func2
执行完了,执行func3
。这就是同步。
那什么是异步呢?异步就是大家各做各的,互不干扰,无需互相等待。
但请注意,各做各的,并不意味着乱序。它们依然是按照顺序执行的。只不过,func1
还没执行完,func2
就已经可以执行了。
那么JavaScript里面有哪些异步函数呢?settimeout
函数、fetch
函数,这些都是异步函数。
2、Promise
Promise中文意思是承诺,在JavaScript里面,你可以通俗地理解为:把这个任务(函数)交给我吧,我来完成。
2.1 Promise是怎么用的
接下来,讲讲Promise是怎么用的。Promise,它是一个类,实例化之后,会生成一个对象。
在下面这个例子中,我创建了p1
,这样一个Promise
对象。构造函数传入一个haha
函数,haha
函数里面又有两个参数,tmp1
和tmp2
。
tmp1
和tmp2
,这俩又分别是两个函数。
(这里会比较绕,没办法,这个语法它就这样,我也很无奈。)
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);
});
tmp1
和tmp2
这两个函数,又可以传参进去。这里我传入了字符串。
当然,也可以传其它的东西进去,例如:传一个对象{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
!”。
之后,调用p1
的then
函数,将tmp1
的结果取出。然后,在p1
的then
函数里,实例化一个新的对象p2
。
p2
给它一个新的settimeout
函数,让它间隔2
秒之后,打印“demo
222
!”。
接着,我再调用p2
的then
函数,将结果取回。
//用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
的理解。
如果你还是觉得很麻烦,不要紧,async
和await
关键字能解决你的痛苦。
3、async和await
Promise的出现确实解决了多个异步函数嵌套的那种繁琐场景。但是,我承认,Promise
用起来确实也没那么简洁。
接下来介绍一下async
和await
,它们是专门用来解决这个问题的。
async
和await
两个关键字是配套使用的。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
函数搞定之后,在外部调用一下,就可以看到它的异步效果了。
如果我们用async
和await
来改写上面那个场景,那就更加清晰、简单了。
我们先定义一个异步函数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下来,在浏览器上运行一下,才能彻底理解它的用法。