阅读 676

结合 async 异步函数 - 提高 Promise 的易用性

前言

异步函数怎么工作的?

  • 开局一张图
    image
async function myAsyncFunc(){
    try {
        const fulfilledValue = await promise
    }catch(rejectValue){
        console.error('error:', rejectValue)
    }
}
复制代码

函数定义之前使用了 async 关键字,就可以在函数内使用 await。 当您 await 某个 Promise 时,函数暂停执行,直至该 Promise 产生结果,并且暂停并不会阻塞主线程。 如果 Promise 执行,则会返回值。 如果 Promise 拒绝,则会抛出拒绝的值。

如何用我们的 async 改写我们的 promise 代码

  • 假如我们这里需要获取一段文字数据
function logFetch(url) {
  return fetch(url)
    .then(response => response.text())
    .then(text => {
      console.log(text);
    }).catch(err => {
      console.error('fetch failed', err);
    });
}
复制代码
  • 下面用 async 异步函数改写
async function logFetch(url) {
  try {
    const response = await fetch(url);
    
    // 打印成功获取的数据
    console.log(await response.text());
  }
  catch (err) {
  
    // 同样的抛出错误
    console.log('fetch failed', err);
  }
}
复制代码

去掉了万恶的 return 回调函数,是不是代码清爽很多了。

异步函数返回值

  • 无论是否使用 await,异步函数都会返回 Promise。该 Promise 解析时返回异步函数返回的任何值,拒绝时返回异步函数抛出的任何值。

因此,对于:

// wait ms milliseconds
function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function hello() {
  await wait(500);
  return 'world';
}
复制代码

…调用 hello() 返回的 Promise 会在执行时返回 "world"。

async function foo() {
  await wait(500);
  throw Error('bar');
}
复制代码

…调用 foo() 返回的 Promise 会在拒绝时返回 Error('bar')。

如果我们想按照顺序获取数据啦?

  • 直接使用 promise
function logInOrder(urls) {
  // 先使用我们上面写好的 fetch 函数获取所有的数据
  const textPromises = urls.map(url => {
    return fetch(url).then(response => response.text());
  });

  // 然后用 reduce 把前面的 promises 一一的进行处理
  textPromises.reduce((chain, textPromise) => {
    return chain.then(() => textPromise)
      .then(text => console.log(text));
  }, Promise.resolve());
}
复制代码
  • 如果使用 async 的话
async function logInOrder(urls) {
  for (const url of urls) {
    const response = await fetch(url);
    console.log(await response.text());
  }
}
复制代码

这样是不是简洁很多,但是这样的话我们的第二次获取数据要在第一次数据获取完毕才能开始,这样就牺牲了性能,但是我们还有更好的方法

async function logInOrder(urls) {
  // 使用 map,和 async 改写,这样可以并行获取数据
  const textPromises = urls.map(async url => {
    const response = await fetch(url);
    return response.text();
  });

  for (const textPromise of textPromises) {
    console.log(await textPromise);
  }
}
复制代码

上面的代码解决了我们并行获取数据的时间问题,又能按照我么你的需求一一按顺序打印我们的数据

使用其他语法

  • 箭头函数
const mySync = async url=> {
  try {
    const response = await fetch(url);
    console.log(await response.text());
  }
  catch (err) {
    console.log('fetch failed', err);
  }
}
复制代码
  • 对象方法
const storage = {
  async getAvatar(name) {
    const cache = await caches.open('avatars');
    return cache;
  }
};

storage.getAvatar('jaffathecake').then(…);
复制代码
  • 如果情况复杂你还可以使用类来改写
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

const storage = new Storage();
storage.getAvatar('jaffathecake').then(…);
复制代码

参考

关注下面的标签,发现更多相似文章
评论