結合 async 異步函數 - 提升 Promise 的易用性

前言

異步函數怎麼工做的?

  • 開局一張圖
    image
async function myAsyncFunc(){
    try {
        const fulfilledValue = await promise
    }catch(rejectValue){
        console.error('error:', rejectValue)
    }
}
複製代碼

函數定義以前使用了 async 關鍵字,就能夠在函數內使用 await。 當您 await 某個 Promise 時,函數暫停執行,直至該 Promise 產生結果,而且暫停並不會阻塞主線程。 若是 Promise 執行,則會返回值。 若是 Promise 拒絕,則會拋出拒絕的值。javascript

如何用咱們的 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 回調函數,是否是代碼清爽不少了。java

異步函數返回值

  • 不管是否使用 await,異步函數都會返回 Promise。該 Promise 解析時返回異步函數返回的任何值,拒絕時返回異步函數拋出的任何值。

所以,對於:web

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

async function hello() {
  await wait(500);
  return 'world';
}
複製代碼

…調用 hello() 返回的 Promise 會在執行時返回 "world"。promise

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

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(…);
複製代碼

參考

相關文章
相關標籤/搜索