其实关于异步的处理,我个人是大体已经明白了其语法及实现方式了,但我就卡在了一个问题上,异步存在的意义是什么?关于这一点。。我想了大概两天(属于是猪脑过载了),然后在晚上打游戏的时候,看着兵线过塔,突然明白了异步是干什么的,于是果断投降,开始了这篇文章。
异步的意义
那么首先追问意义前,先要知道异步是啥。我先写一段同步代码:
console.log(1);console.log(2);console.log(3);
那么在控制台中,输出的就是 1 2 3
接下来看下面这段异步代码:
console.log(1);let time = setTimeout(() => {console.log(2)},0);console.log(3)
ok,那么这段代码的输出是什么呢?答案是 1 3 2
由此可以看出,所谓同步就是按照顺序,从上而下,一种存在阻塞的编码。而异步打破了这种规律,是一种非阻塞的编程。
虽然我写的这个代码很简单,但我觉得已经充分说明了问题。因为JavaScript是一种自上而下编译的代码,所以就有一个先来后到的规则,就假如马路上都是小轿车,这时候突然开进来一台重型卡车,那么是不是会造成堵塞?如果这辆卡车不开过去,那后面的小轿车是否就无法正常运行?这里的意义也是一样,在JavaScript中,也有函数会长期占用车道,比如延时器函数等,那么这里就需要异步的存在,来将那些特殊的函数挂起,在需要运行或同步完成后再进行。
Promise对象
在上述代码中,我使用了延时器函数来完成异步的操作,但这是特例,并不是说所有函数都能自主的完成异步操作。而在实际编程中,我们也并不总是要代码自上而下执行,总有几个特殊任务是需要挂起的,这时候,就需要用的ES6提供的一个对象Promise对象。
promise是一个对象,同时也是一个构造函数,通过promise可以new一个实例来帮助完成异步的处理,基本语法是:
let demo = new Promise((resolve,reject) => {})
这里不熟悉回调函数的可能会有点懵逼,如果懵逼的话我的建议是先不学习ES6。。因为真的会晕掉的,看不懂又硬看,进度真的很慢。
promise中以回调函数作为参数,而回调函数中传入两个函数作为第二和第二参数,这两个中,第一个参数resolve代表符合条件时触发的逻辑,reject作为不符合条件时触发的参数。那么下面我简单的定义一个布尔值来补全这段代码:
let isRun = true;
let demo = new Promise((resolve,reject)=> {
if (isRun) {
resolve();
}else{
reject();
}
})
// 好了,到这里如果能看懂,那么可以继续看,看不懂的我就建议你反复阅读上面内容或者remake。。
在上面代码中,我们就基本完整创建了一个异步实例,我们接下来就可以调用这个实例来处理我们需要异步的函数。
then()方法
该方法是由promise对象提供的方法,我先抄一段大佬的解释:then可以接收构造函数中处理的状态变化,并分别对应执行。then方法有2个函数参数,第一个函数接收resolved(promise状态为成功)的执行,第二个函数接收reject(promise状态为失败)的执行。
这里对于基础不太好的人,可能又要晕了,所以其实可以不用纠结这段话中的状态什么的,我们只要明白,接下来我们必须使用then()才能完成异步的操作。上代码:
let isRun = true;
let demo = new Promise((resolve,reject)=> {
if (isRun) {
resolve('成功!');
}else{
reject();
}
})
demo.then(
(res) => {
console.log(res);
},
(err) => {
console.log('失败了');
}
)
这里应该能看到then的使用过程了,在then中应用了两个回调函数作为参数,其中第一个参数接收执行成功后返回的resolve,其实也就是resolve。
这里有关于resolve的形参传递的一个问题,我这里直接标注出来便于理解:
应该很清晰了,前面实例的resolve的参数传入了then中。这里要明白我的res到底是哪里来的。
catch()方法
catch()方法是用来捕捉promise状态为失败的函数,该函数只有一个回调函数作为参数,也就是返回错误信息。该函数可写可不写,因为then中的第二个函数也可以作为状态失败调用的函数。不过如果逻辑不是很清晰的话,可以让then()专门返回成功状态,catch()专门返回失败状态。所以前面的代码可以写成:
let isRun = true;
let demo = new Promise((resolve,reject)=> {
if (isRun) {
resolve('成功!');
}else{
reject();
}
})
demo.then(
(res) => {
console.log(res);
}
).catch(
(err) => {
console.log('失败了');
}
)
这里是用链式结构写的,不会的可以查一下什么是链式结构,或者直接分开写。
p.s.这里说一下还有个finally函数,就是在promise执行完毕(无论成功与否)后调用的函数,但我查了一下,该函数并被标准函数,我也不知道是否支持,所以就不写了,感兴趣的可以查一下。
封装Promise
let getPromise = (demo) => {
return new Promise((resolve,reject) => {
if (demo) {
resolve('成功');
}else{
reject('失败')
}
})
}
let demo = getPromise(true)
demo.then(
(res) => {
console.log(res);
}
)
这里就是普遍的写法,看到这里给我说看不懂的建议死刑
ok,到这里应该就差不多,基本的写法是已经有了,如果是小白只想理解promise是啥的,看到这里就行了,如果是正儿八经学习的,那可以继续看一下。
async[ə'zɪŋk]和await(暂时简写)
async/await是什么
async/await 是ES7提出的基于Promise的解决异步的最终方案。
async
async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。因此对async函数可以直接then,返回值就是then方法传入的函数。
await
await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待。
await 修饰的如果是Promise对象:可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语句才会往下执行;
如果不是Promise对象:把这个非promise的东西当做await表达式的结果。
async/await 的正确用法