1. 程式人生 > >理解ES7中的async/await

理解ES7中的async/await

def 需求 一個表 來看 1-1 運算符 get 執行 表達

理解ES7中的async/await

優勢是:就是解決多層異步回調的嵌套

 從字面上理解 async/await, async是 "異步"的含義,await可以認為是 async wait的簡寫,因此可以理解 async 用於聲明一個function是異步的,而await用於等待一個異步方法執行完成返回的值(返回值可以是一個Promise對象或普通返回的值)。
註意:await 只能出現在 async函數中。

1-1 async的作用?
首先來理解async函數是怎麽處理返回值的,我們以前寫代碼都是通過return語句返回我們想要的值,但是async與return有什麽區別呢? 下面我們看如下代碼:

async function testAsync() {
  return ‘hello world‘;
}
const result = testAsync();
console.log(result);  // 打印出來看到 返回一個promise對象

如上代碼,我們輸出的是一個Promise對象。因此 async返回的是一個Promise對象,因此我們可以使用 then()鏈來處理這個Promise對象。像如下代碼:

async function testAsync() {
  return ‘hello world‘;
}
const result = testAsync();
result.then(v 
=> { console.log(v); // 輸出 hello world });

但是如果 async函數沒有返回值的話,那麽就會返回 undefined; 如下代碼:

async function testAsync() {
  return;
}
const result = testAsync();
result.then(v => {
  console.log(v);  // 輸出 undefined
});

1-2 await的作用?
從語義上說,await是在等待一個async函數完成的,async函數返回的是一個Promise對象,await等待的是一個表達式,這個表達式的計算結果是Promise對象或其他值。

async函數返回一個Promise對象,await作用是用於等待一個async函數的返回值。
await函數後面可以接普通函數調用或直接量,請看如下代碼:

function getSomething() {
  return ‘something‘;
}

async function testAsync() {
  return Promise.resolve(‘hello‘);
}

async function test () {
  const v1 = await getSomething();
  const v2 = await testAsync();
  console.log(v1);  // something
  console.log(v2);  // hello
}
test();

註意:await 是等待async函數返回的Promise對象或其他值,await是一個運算符,用於組成表達式, 如果等待的是一個Promise對象,await會阻塞後面的代碼(async調用不會造成堵塞,它內部所有的堵塞
都被封裝在一個Promise對象中異步執行),等待Promise對象的resolve,然後得到resolve的值,作為await表達式的運輸結果。

1-3 async/await 的一起使用的作用及優勢在哪?
我們先不用 async/await, 來看看使用setTimeout模擬異步操作如下代碼:

var test = function(time) {
  return new Promise((resolve, reject) => {
    setTimeout(function(){
      resolve(‘hello world‘);
    }, time)
  });
};

test(1000).then((v) => {
  console.log(v);
});

如果改用 async/await 代碼如下:

var testAsync = function(time) {
  return new Promise((resolve, reject) => {
    setTimeout(function(){
      resolve(‘hello world‘);
    }, time)
  });
};

async function test(time) {
  const v = await testAsync(time);
  console.log(v); // hello world
}
test(1000);

看上面的代碼,反而會覺得 使用 async/await 代碼變得多一點,復雜一點,但是結果貌似都一樣,那麽使用 async/await的優勢在哪?

1-4 async/await的優勢在於處理then鏈

單一的Promise鏈貌似不能發現 async/await的優勢,但是如果需要處理多個Promise組成的then鏈的時候,優勢可以看出來,因為Promise是通過then鏈來解決多層回調的問題,現在我們又可以使用
async/await來進一步優化,他們的優點就是解決多層異步回調的嵌套。

假設我們現在有一個需求是,分多個步驟完成,每個步驟都是異步的,並且後面的異步都需要依賴於上一個異步回調返回的數據,進行往下傳遞。我們先用 setTimeout來模擬異步操作。

function useTimeout (t) {
  return new Promise((resolve, reject) => {
    setTimeout(()=> {
      resolve(t+100)
    }, t);
  });
}

function step1(t) {
  console.log(`step1 with ${t}`); // step1 with 300
  return useTimeout(t);
}

function step2(t) {
  console.log(`step2 with ${t}`); // step2 with 400
  return useTimeout(t);
}

function step3(t) {
  console.log(`step3 with ${t}`); // step3 with 500
  return useTimeout(t);
}

function test() {
  const time1 = 300;
  step1(time1)
    .then(time2 => step2(time2))
    .then(time3 => step3(time3))
    .then(res => {
      console.log(`result is ${res}`);  // result is 600
    })
} 
test();

如果我們使用 async/await來實現,代碼變為如下:

function useTimeout (t) {
  return new Promise((resolve, reject) => {
    setTimeout(()=> {
      resolve(t+100)
    }, t);
  });
}

function step1(t) {
  console.log(`step1 with ${t}`); // step1 with 300
  return useTimeout(t);
}

function step2(t) {
  console.log(`step2 with ${t}`); // step2 with 400
  return useTimeout(t);
}

function step3(t) {
  console.log(`step3 with ${t}`); // step3 with 500
  return useTimeout(t);
}

async function test() {
  const time1 = 300;
  const time2 = await step1(time1);
  const time3 = await step2(time2);
  const result = await step3(time3);
  console.log(`result is ${result}`);
} 
test();

上面我們可以看到 使用async/await 代碼看起來都是同步的,等第一步完成後,再執行第二步,依次類推..... 並且不需要更多的回調函數嵌套。

下面我們再來看下我們之前講的,後面的步驟需要上一個步驟的結果傳遞進去,使用async/await的優勢可能更明顯。
如下代碼:

function useTimeout (t) {
  return new Promise((resolve, reject) => {
    setTimeout(()=> {
      resolve(t+100)
    }, t);
  });
}

function step1(t1) {
  console.log(`step1 with ${t1}`); // step1 with 300
  return useTimeout(t1);
}

function step2(t1, t2) {
  console.log(`step2 with ${t1} and ${t2}`); // step2 with 300 and 400
  return useTimeout(t1+t2);
}

function step3(t1, t2, t3) {
  console.log(`step3 with ${t1} and ${t2} and ${t3}`); // step3 with 300 and 400 and 800
  return useTimeout(t1+t2+t3);
}

async function test() {
  const time1 = 300;
  const time2 = await step1(time1);
  const time3 = await step2(time1, time2);
  const result = await step3(time1, time2, time3);
  console.log(`result is ${result}`);  // result is 1600
} 
test();

1-5 捕捉錯誤
我們可以使用 try catch 來捕獲錯誤,如下代碼:

var sleep = function (time) {
  return new Promise((resolve, reject) => {
    setTimeout(function() {
      // 出錯了, 返回 error
      reject(‘error‘);
    }, time);
  })
};

var start = async function() {
  try {
    console.log(‘start‘);
    await sleep(3000); // 返回一個錯誤
    // 下面代碼不會被執行
    console.log(‘end‘);
  } catch (err) {
    console.log(err); // 捕捉錯誤 error 
  }
};

start();

理解ES7中的async/await