携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情
回调函数、generate、promise、async都是JS单线程的解决方案,是一步一步进行优化的。
回调函数、generate、promise、async区别
回调函数 callback
- 回调地狱,无法用try...catch捕获,不能返回值
- 回调地狱的根本问题在于:
- 缺乏顺序性: 回调地狱导致的调试困难,和大脑的思维方式不符
- 嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身,即(控制反转)
- 嵌套函数过多的多话,很难处理错误
promise
- 为了解决callback的问题而产生的,改成了链式调用,每次都返回全新 Promise
- 虽然解决了回调地狱,但.then的回调还是存在
- 无法取消
Promise,错误需要通过回调函数捕获,而且.catch只能捕获最近一次的then错误。
Generator
可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。可以控制函数的执行,可以配合 co 函数库使用
async
async 是Generator 函数的语法糖
- async、await 是异步的终极解决方案
- Async函数的实现最简洁,最符合语义,代码清晰,不用像 Promise 写一大堆 then 链,处理了回调地狱的问题
异步各个解决方案的错误捕获
Generator
- 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。
function* gen(x){
try {
var y = yield x + 2;
} catch (e){
console.log(e);
}
return y;
}
var g = gen(1);
g.next();
g.throw('出错了');
// 出错了
promise
- .catch里处理
async
- 只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的 回调函数
- 返回的是promise,在函数.then(()=>{}, e=>{错误处理})。但是这种做法有个问题,只要async里有一个await后的promise返回的状态是reject,就会进入错误捕获,而且不会继续执行后面的代码
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
- 有的时后,即使前一个异步操作失败,我们也不要中断后面的代码执行。这时可以将第一个 await 放在 try...catch 里,这样不管这个异步操作是否出错,第二个 await 都会执行。
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
await Promise.resolve('hello world');
}
- 或者,在每个await的Promise的catch里捕获
async function f() {
await Promise.reject('出错了').catch(e => {console.log('ee', e)})
await Promise.resolve('hello world');
}