回调函数、generate、promise、async的区别

131 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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');
}