1. 程式人生 > >非同步神器--async

非同步神器--async

一、含義

學過ES6的同學大概都熟悉Generator函式,那麼async可以說是Generator的語法糖,它讓非同步操作變得更加方便。

二、語法特點

const asyncDemo = async function () {
    await fn();
    await fn2();
    await fn3();
    
}

asyncDemo();

可以看出async函式在宣告的時候要加上async表示這個函式內有非同步操作,函式體內每一個await表示跟在其後面的表示式需要等待結果,在這裡我們可以進行非同步操作。await後面可以是Promise物件和原始型別的值(但這是等同於同步操作)

值得一提的是async函式可以像普通函式一樣直接呼叫,例如上面的asyncDemo(),這和Generator就不一樣了。而且async函式返回的是Promise物件,這樣的話我們就可以使用then方法指定下一步的操作。由於async函式返回的 Promise 物件,必須等到內部所有await命令後面的 Promise 物件執行完,才會發生狀態改變,除非遇到return語句或者丟擲錯誤。也就是說,只有async函式內部的非同步操作執行完,才會執行then方法指定的回撥函式。

下面是一個例子:

async function f() {
  await Promise.reject('出錯了');
  await Promise.resolve('hello world'); // 不會執行
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出錯了

可以看到當async函式在遇到錯誤時便會中斷接下來的非同步操作,但是有時候我們不希望在出現錯誤時中斷程式,這個時候我們就可以使用try...catch結構了。如下:

async function f() {
  try {
    await Promise.reject('出錯了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// hello world

三、使用形式

// 函式宣告
async function foo() {}

// 函式表示式
const foo = async function () {};

// 物件的方法
let obj = { async foo() {} };
obj.foo().then(...)

// Class 的方法
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('jake').then(…);

// 箭頭函式
const foo = async () => {};

四、async的小demo

讓ajax請求按順序執行

        const timeout = ms => new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve();
            }, ms);
        });
       //假設ajax1,ajax2,ajax3是我們所需要要ajax請求
        const ajax1 = () => timeout(2000).then(() => {
            console.log('1');
            return 1;
        });

        const ajax2 = () => timeout(1000).then(() => {
            console.log('2');
            return 2;
        });

        const ajax3 = () => timeout(2000).then(() => {
            console.log('3');
            return 3;
        });

        const ajaxRequests = ajaxArray => {
        	var data = [];
        	async function test() {
        		for (let request of ajaxArray){
        			try{
        				let val = await request();
        				data.push(val);
        			}catch(err){
        				console.log('error');
        			}
            	}
        	}
        	async function result(){
        		await test();
        		return data;
        	}
        	return result();
        };

        ajaxRequests([ajax1, ajax2, ajax3]).then(data => {
            console.log('done');
            console.log(data); // data 為 [1, 2, 3]
        });

當然這個是針對互相依賴的非同步操作,因為只有ajax1請求完之後才會執行ajax2....,如果是互不依賴的最好讓他們同時觸發這樣比較省時(可以使用Promise.all方法)。