Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

es6-async函数 #22

Open
wozien opened this issue Oct 21, 2020 · 0 comments
Open

es6-async函数 #22

wozien opened this issue Oct 21, 2020 · 0 comments
Labels

Comments

@wozien
Copy link
Owner

wozien commented Oct 21, 2020

在es6中引入了PromiseGenerator 函数的概念方便我们更加快速优化的实现异步编程,但是生成器的运行依赖于自动执行函数或者co模块。所以在es7引入了 async 函数,使异步操作更加方便。

基本用法

我们可以把 async 函数看作是自动执行 Generator 函数的语法糖:

async function fn(args) {

}
// 等价于
function fn(args) {
  return run(function*() {
  
  });
}

我们只要在普通函数前面加上 async 关键字,在函数体里面把 yield 替换成await。按正常函数调用方式即可执行按顺序执行异步任务。所以之前的gen()异步任务可以改写成:

function fetchData(url) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({ code: 0, data: url });
    }, 1000);
  });
}

async function gen() {
  let res1 = await fetchData('http://www.baidu.com');
  let res2 = await fetchData('http://www.inoob.xyz');
  return res1.data + ' ' + res2.data;
}

gen().then(data => console.log(data));

由上面的代码可见,async 函数返回一个 Promise。函数内部的return值成为then() 成功处理函数的参数。

await 后面如果是一个 Promise 对象,会返回对象的 resolve() 或者reject() 的结果。否则直接返回结果:

async function fn() {
  let a = await Promise.resolve(1);
  let b = await 2;
  return a + b;
}

fn().then(v => console.log(v));   // 3

async 函数抛出错误,会被返回的 Promisecatch() 方法捕捉:

async function fn() {
  await Promise.resolve(1);
  throw new Error('boom');
}

fn()
  .then(v => console.log(v))
  .catch(e => console.log(e.message)); // boom

另外 await 后面的 resolve() 的返回值必须 return 才能被 then() 获取,而 reject() 则不用。并且 reject() 后,函数将会中断执行:

async function fn() {
  await Promise.reject(1);
  throw new Error('boom'); // 不会执行
}

fn()
  .then(null, v => console.log(v)) // 1
  .catch(e => console.log(e.message)); 

错误处理

因为await 后面的 Promise 状态失败会导致整个函数中断,于是可以在try...catch 中捕获:

async function fn() {
  try {
    await Promise.reject(new Error('boom'));
  } catch (e) {
    //
  }
  return await Promise.resolve(1);
}

fn()
  .then(v => console.log(v))  // 1
  .catch(e => console.log(e.message));

另一种方式是在 await 后面的 Promise 对象的后面再跟上一个 catch() 方法:

async function fn() {
  await Promise.reject(new Error('boom')).catch(e => {});
  return await Promise.resolve(1);
}

fn()
  .then(v => console.log(v)) // 1
  .catch(e => console.log(e.message));

并发执行

await 后面的异步任务如果没有先后顺序,最好让他们并发执行:

async function fn() {
  let res1 = await getName();
  let res2 = await getMaxListeners();
  return [res1.data, res2.data];
}

应该写成下面方式:

async function fn() {
  let p1 = getName();
  let p2 = getMaxListeners();
  let res1 = await p1;
  let res2 = await p2;
  return [res1.data, res2.data];
}

或者利用 Promise.all() 的方式:

async function fn() {
  let p1 = getName();
  let p2 = getMaxListeners();
  let [res1, res2] = await Promise.all([p1, p2]);
  return [res1.data, res2.data];
}

异步处理比较

对于 Promiseasync 两者其实没有什么可比性,后者其实是需要依赖前者。只是有了 async 让异步编码更加优雅:

function fetch() {
  return fetchData()
  .then(data => {
    if (data.moreData) {
        return fetchAnotherData(data)
        .then(moreData => {
          return moreData
        })
    } else {
      return data
    }
  });
}

// 用async改写
async function fetch() {
  const data = await fetchData()
  if (data.moreData) {
    const moreData = await fetchAnotherData(data);
    return moreData
  } else {
    return data
  }
};

对于和 Generator 比较,我认为在异步处理方面是可以取代它的,毕竟方便更多。但是Generator 还有其他方面的应用,比如更加方便的实现迭代器。

参考

ES6 系列之我们来聊聊 Async

@wozien wozien added the es6 label Oct 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant