在日常代码中我们处理异步最多的估计就是回调函数,一层套一层,无间套,超过3层就会疯。
于是Promise出现了,他的出现解放了无间套,变成了then方法的堆叠,对于效率提升了非常大,但是,当过多的then方法堆在一起后,代码也不容易阅读了。
于是Generator出现了,写出来的代码也美观,但对于异步没有自动执行器,需要手动,或者再写一个自动执行器,当然有现成的co模块使用,还是没那么完美。
于是async函数出现了,问题统统解决,代码美观,还会自动执行,跟写同步代码一样,太方便了。
当然在现实中,大部分人其实用promise最多,因为超九成的开发者处理异步一般来说就是一层:主要就是接口请求,然后处理返回数据。用Promise已经完全能够胜任,现在有些人动不动就一定要别人使用async,说用Promise太落伍了,我个人认为,如果业务不复杂,用什么是个人选择,没有什么高低之分,如果业务复杂,这里就建议使用async。
下面我们介绍一下这几种常用的异步处理方法。
以下所有示例直接使用setTimeout来模拟异步操作,方便测试。
回调无间
function timeProgressPromise(index, time, callback) {
setTimeout(() => {
callback(`通过${time}ms,第${index}步骤完成`);
}, time)
}
timeProgressPromise(1, 1000, (res1) => {
console.log(res1);
timeProgressPromise(2, 1500, (res2) => {
console.log(res2);
timeProgressPromise(3, 2000, (res3) => {
console.log(res3);
});
});
});
// 通过1000ms,第1步骤完成
// 通过1500ms,第2步骤完成
// 通过2000ms,第3步骤完成
我们可以看到这个一层套一层的写法,如果少其实还挺好看的,只是一多就不好管理了,优点是任何异步都可以用回调处理。
Promise
想用Promise那么就要把异步过程包装成Promise对象。
function timeProgressPromise(index, time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`通过${time}ms,第${index}步骤完成`);
}, time)
})
}
timeProgressPromise(1, 1000)
.then(data => {
console.log(data);
return timeProgressPromise(2, 1500);
})
.then(data => {
console.log(data);
return timeProgressPromise(3, 2000);
})
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
});
// 通过1000ms,第1步骤完成
// 通过1500ms,第2步骤完成
// 通过2000ms,第3步骤完成
我们可以看到通过每次then方法返回一个新的Promise就可以这样无限下去,已经非常方便了,唯一缺点就是把每次的返回数据隔离了,上一层的返回数据无法直接用在下一层,必须通过参数传下去或者中转变量。
Generator生成器
这里需要一个run方法来自动执行Generator。
- 如果不太熟悉建议先看Generator 函数的语法。
- 如果有学习过但是有点忘记了,可以看另一篇Generator函数简单记录找回记忆。
function timeProgressPromise(index, time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`通过${time}ms,第${index}步骤完成`);
}, time)
})
}
function* myFileRead() {
let step1 = yield timeProgressPromise(1, 1000);
console.log(step1);
let step2 = yield timeProgressPromise(2, 2000);
console.log(step2);
let step3 = yield timeProgressPromise(3, 1500);
console.log(step3);
}
function run(fn) {
var gen = fn();
function next(data) {
let res = gen.next(data);
if (res.done) return;
res.value.then(data => {
next(data);
})
}
next();
}
run(myFileRead);
// 通过1000ms,第1步骤完成
// 通过1500ms,第2步骤完成
// 通过2000ms,第3步骤完成
async函数
function timeProgressPromise(index, time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`通过${time}ms,第${index}步骤完成`);
}, time)
})
}
async function myProgress() {
let p1 = await timeProgressPromise(1, 1000);
console.log(p1);
let p2 = await timeProgressPromise(2, 2000);
console.log(p2);
let p3 = await timeProgressPromise(3, 1000);
console.log(p3);
}
myProgress();
// 通过1000ms,第1步骤完成
// 通过1500ms,第2步骤完成
// 通过2000ms,第3步骤完成
小结
喜欢用哪个就用哪个,但是当你用一种方式很吃力了,建议换另一种处理方式。
生活愉快!