1. 程式人生 > 其它 >【CF212E】IT Restaurants (01揹包問題)

【CF212E】IT Restaurants (01揹包問題)

async函式

基本概念

async 函式是什麼?一句話,它就是 Generator 函式的語法糖。

將上一章的程式碼改成 async 函式的版本:

const { promisify } = require("util");
const path = require('path')
const file1 = path.join(__dirname, './text/1.txt')
const file2 = path.join(__dirname, './text/2.txt')
const readFileP = promisify(readFile)

function* f() {
  let data1 = yield readFileP(file1)
  console.log('耶,完成了1,資料是' + data1);
  let data2 = yield readFileP(file2)
  console.log('耶,完成了2,資料是' + data2);
}

//async函式的版本
async function f() {
  let data1 = await readFileP(file1)
  console.log('耶,完成了1,資料是' + data1);
  let data2 = await readFileP(file2)
  console.log('耶,完成了2,資料是' + data2);
}

比較後就會發現,async函式的版本就是將 Generator 函式的星號(*)替換成async,將yield替換成await

定義async函式

使用async關鍵字定義一個async函式:

async function f() {
  let data1 = await readFileP(file1)
  console.log('耶,完成了1,資料是' + data1);
  let data2 = await readFileP(file2)
  console.log('耶,完成了2,資料是' + data2);
}

執行async函式

執行async函式則相當於執行了一個自動執行

的Generator函式,async函式如果返回的結果不是Promise,則會執行結果包裝成一個Promise返回:

async function f() {
  console.log(1);
}
f().then(()=>{
  console.log(2);
})

async function f() {
  console.log(1);
  return 'done'
}

f().then(value => {
  console.log(value);
})

await關鍵字

yield類似,async函式中可以使用await關鍵字,await關鍵字後面一般會寫一個Promise例項,async

函式執行的過程中,每次遇到await關鍵字,會將控制權轉回外部環境

  1. 如果await後面是Promise例項,則會等到該 Promise例項被resolve後,才會把本次await到下次await之間的程式碼推到MircoTask(微任務)中等待執行,並且await的返回值是該Promise例項resolve的值
  2. 如果await後面不是Promise例項,則會立即將本次await到下次await之間的程式碼推到MircoTask(微任務)中等待執行,並且await的返回值是等於await後面表示式的值:
async function f() {
  let data = await new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('a')
    }, 2000)
  })
  console.log(data);
}

//f()
//console.log('end')

如果await後面不是Promise 例項

async function f() {
  let data = await 'a'
  console.log(data);
}
f()
console.log('end'); 
//end
//a

async函式的錯誤處理

如果Promise被reject或丟擲錯誤,await之後的程式碼不會執行,因此,需要使用try..catchawait進行錯誤捕捉:

async function f() {
  try {
    let data = await new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('123')
      }, 2000)
    })
    //後續程式碼無法執行
    console.log('done');
  }catch (e) {
    console.log('發生錯誤:',e);
  }
}
f()

async函式處理併發非同步任務

如果,async函式中的每個await都是等到前面await resolve後才會執行,如果想併發執行,可以使用Promise.all:

/*併發處理非同步*/
async function f() {
  let time1 = new Date()
  let [data1,data2] = await Promise.all([
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('123')
      }, 2000)
    }),
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('123')
      }, 3000)
    })
  ])
  console.log(data1,data2,'用時:'+ (new Date() - time1));
}
f()

async函式與Promise的對比

async函式寫非同步邏輯相比Promise會更加簡潔,在處理不同非同步結果相互依賴,錯誤處理,if...else分支等情況時更加簡便:

const {readFile} = require('fs')
const { promisify } = require("util");
const path = require('path')
const file1 = path.join(__dirname, './text/1.txt')
const file2 = path.join(__dirname, './text/2.txt')
const file3 = path.join(__dirname, './text/3.txt')
const readFileP = promisify(readFile)

function f1() {
  readFileP(file1).then(data1 =>{
    console.log('耶,完成了1,資料是' + data1);
    return readFileP(file2)
  }).then(data2 => {
    console.log('耶,完成了1,資料是' + data2);
    return readFileP(file3)
  }).then(data3 => {
    console.log('耶,完成了1,資料是' + data3);
  })
}

async function f2() {
  let data1 = await readFileP(file1)
  console.log('耶,完成了1,資料是' + data1);
  let data2 = await readFileP(file2)
  console.log('耶,完成了2,資料是' + data1 + data2);
  let data3 = await readFileP(file3)
  console.log('耶,完成了2,資料是' + data1 + data2 + data3);

}
f()