async原理解析

目錄

  • async函數是什麼
  • async函數原理
  • 常見的關於async的筆試題

async函數

const fs = require('fs');

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error){
          return reject(error);
        } 
        resolve(data);
    });
  });
};

const foo = function* () {
  const f1 = yield readFile('/src/lib');
  const f2 = yield readFile('/src/utils');

  console.log(f1.toString());
  console.log(f2.toString());
};

把上面代碼的Generator函數 foo 能夠寫成 async 函數,就是這樣:異步

const asyncReadFile = async function () {
  const f1 = yield readFile('/src/lib');
  const f2 = yield readFile('/src/utils');

  console.log(f1.toString());
  console.log(f2.toString());
};

能夠發現, async函數就是將Generator函數的星號(*)替換成async,將 yield替換成 await,僅此而已。async

async函數是基於 Generator的改進,體如今如下4點函數

1 . 內置執行器。
Generator函數的執行必須靠執行器。因此纔有了 Thunk函數和co模塊,而 async函數自帶執行器。async函數的執行和普通函數同樣。ui

asyncReadFile();

2 . 更好的語義。
asyncawait,比起星號和yield,語義更清楚了。
async表示函數裏有異步操做,await表示緊跟在後面的表達式須要等待結果。spa

3 . 更廣的適應性。
即便 Generator函數能夠藉助co模塊自動執行,可是co模塊後面只能是 Thunk函數或Promise對象,而async函數的await命令後面,能夠是 Promise對象和原始類型的值(數值、字符串和布爾值,但這是會自動轉成當即 resolvedPromise對象線程

4 . 返回值是 Promise
aysnc函數返回值爲 Promise,這比Generator函數的返回值是Iterator對象方便多了。code

async函數徹底能夠看做多個異步操做,包裝成的一個 Promise 對象,而await命令就是內部then命令的語法糖。協程

老是就是 Generator 函數雖然是JS借鑑其餘語言,根據JS自己單線程的特色實現的協程,可是使用起來會麻煩不少,而 async函數就是爲了解決這麼麻煩而生的。其實 async函數就是將 Generaor函數和自動執行器包裝了在了一塊兒,而後潤色了一下。

async函數的實現原理

就是將Generator函數和自動執行器,包裝在一個函數裏。對象

async function fn(args) {
    // ...
}
function fn(args) {
    return spawn(function* () {
        // ...
    })
}

全部的 async 函數均可以寫成上面的第二種形式,其中 spawn 函數就是自動執行器。接口

function spawn(genF) {
  return new Promise(function(resolve, reject) {
    const gen = genF();
    function step(nextF) {
      let next;
      try {
        next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}

常見的關於async的筆試題

  • 實現一個sleep
  • 實現一個紅綠燈: 紅燈2秒,黃燈1秒,綠燈3秒
  • 使用 async 實現 Promise.all()的效果

實現一個 sleep

每隔1秒輸出 1, 2, 3, 4, 5

function sleep(interval) {
    return new Promise(resolve => {
        setTimeout(resolve, interval);
    })
}

// 用法
async function one2FiveInAsync() {
    for (let i = 1; i <= 5; i++) {
        console.log(i);
        await sleep(1000);
    }
}
one2FiveInAsync();

實現一個紅綠燈

紅燈2秒,黃燈1秒,綠燈3秒

function sleep(duration) {
    return new Promise(resolve => {
        setTimeout(resolve, duration);
    })
}
async function changeColor(color, duration) {
    console.log('當前顏色', color);
    await sleep(duration);
}
async function main() {
    await changeColor('紅色', 2000);
    await changeColor('黃色', 1000);
    await changeColor('綠色', 3000);
}
main();

使用 async 實現 Promise.all()的效果

// 寫法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 寫法二
let fooPromise = getFoo();
let barPromise = getBar();

let foo = await fooPromise;
let foo = await barPromise;

上面兩種寫法,getFoo 和 getBar 都是同時觸發的,這樣就會縮短程序的執行時間。

上面只是簡單示例,思考一下,寫出完成代碼。

總結

  • async 函數原理就是 Generator函數 和 自動執行器包裝了一下。
  • Generator就是能夠暫定執行和在以前停下的位置接着執行。好比發送一個接口請求,發出以後,JS能夠去幹其餘的事兒,接口請求回來以後(數據經過next傳入),會接着繼續執行。可是它不能自動執行,因此須要自動執行器, thunk函數和co模塊都是,可是async給咱們封裝得更加完美。
相關文章
相關標籤/搜索