Wb saib Async/Await hauv JavaScript siv piv txwv

Tus sau tsab xov xwm tshuaj xyuas cov piv txwv ntawm Async/Await hauv JavaScript. Zuag qhia tag nrho, Async / Await yog txoj hauv kev yooj yim los sau cov lej asynchronous. Ua ntej qhov tshwj xeeb no tshwm sim, cov cai no tau sau nrog kev hu rov qab thiab cov lus cog tseg. Tus sau ntawm thawj tsab xov xwm qhia txog qhov zoo ntawm Async/Await los ntawm kev tshuaj xyuas ntau yam piv txwv.

Peb nco qab: rau txhua tus neeg nyeem Habr - 10 ruble luv nqi thaum tso npe rau hauv ib chav kawm Skillbox siv Habr promo code.

Skillbox pom zoo: Kev kawm online chav kawm "Java developer".

callback

Callback yog ib txoj haujlwm uas nws hu tau ncua sijhawm tsis kawg. Yav dhau los, callbacks tau siv nyob rau hauv cov cheeb tsam ntawm cov cai uas qhov tshwm sim tsis tuaj yeem tau txais tam sim ntawd.

Nov yog ib qho piv txwv ntawm asynchronously nyeem cov ntaub ntawv hauv Node.js:

fs.readFile(__filename, 'utf-8', (err, data) => {
  if (err) {
    throw err;
  }
  console.log(data);
});

Teeb meem tshwm sim thaum koj xav tau ua ntau yam haujlwm asynchronous ib zaug. Cia peb xav txog qhov xwm txheej no: qhov kev thov yog ua rau Arfat tus neeg siv cov ntaub ntawv, koj yuav tsum nyeem nws qhov profile_img_url thiab rub tawm cov duab los ntawm someserver.com server.
Tom qab rub tawm, peb hloov cov duab mus rau lwm hom, piv txwv li los ntawm PNG rau JPEG. Yog tias qhov kev hloov pauv tau ua tiav, tsab ntawv raug xa mus rau tus neeg siv email. Tom ntej no, cov ntaub ntawv hais txog qhov xwm txheej yog nkag mus rau hauv cov ntaub ntawv transformations.log, qhia hnub tim.

Nws yog ib qho tsim nyog yuav tsum tau them sai sai rau qhov sib tshooj ntawm callbacks thiab ntau tus lej }) nyob rau hauv qhov kawg ntawm cov cai. Nws hu ua Callback Hell lossis Pyramid of Doom.

Qhov tsis zoo ntawm txoj kev no yog pom tseeb:

  • Txoj cai no nyuaj nyeem.
  • Nws kuj yog ib qho nyuaj rau kev ua yuam kev, uas feem ntau ua rau cov lej tsis zoo.

Txhawm rau daws qhov teeb meem no, cov lus cog tseg tau ntxiv rau JavaScript. Lawv tso cai rau koj los hloov qhov sib sib zog nqus nesting ntawm callbacks nrog lo lus .ces.

Qhov zoo ntawm cov lus cog tseg yog tias lawv ua kom cov cai nyeem tau zoo dua, los ntawm sab saum toj mus rau hauv qab es tsis yog los ntawm sab laug mus rau sab xis. Txawm li cas los xij, cov lus cog tseg kuj muaj lawv cov teeb meem:

  • Koj yuav tsum tau ntxiv ntau .thov.
  • Hloov chaw sim / ntes, .catch yog siv los daws txhua qhov yuam kev.
  • Ua haujlwm nrog ntau cov lus cog tseg hauv ib lub voj tsis yog ib txwm yooj yim; qee zaum, lawv nyuaj rau cov cai.

Ntawm no yog ib qho teeb meem uas yuav qhia lub ntsiab lus ntawm lub ntsiab lus kawg.

Piv txwv tias peb muaj lub voj voog uas luam tawm ib ntu ntawm cov lej ntawm 0 txog 10 ntawm qhov sib txawv (0–n vib nas this). Siv cov lus cog tseg, koj yuav tsum tau hloov lub voj no kom cov lej luam tawm hauv ntu ntawm 0 mus rau 10. Yog li, yog tias nws siv sijhawm 6 vib nas this los luam tus xoom thiab 2 vib nas this los luam ib qho, tus lej yuav tsum tau luam tawm ua ntej, thiab tom qab ntawd. lub countdown rau luam ntawv yuav pib.

Thiab tau kawg, peb tsis siv Async/Await lossis .sort los daws qhov teeb meem no. Ib qho piv txwv daws yog thaum kawg.

Async muaj nuj nqi

Qhov sib ntxiv ntawm async functions hauv ES2017 (ES8) ua kom yooj yim txoj haujlwm ntawm kev ua haujlwm nrog cov lus cog tseg. Kuv nco ntsoov tias cov haujlwm async ua haujlwm "sab saum toj" ntawm cov lus cog tseg. Cov haujlwm no tsis sawv cev rau cov ntsiab lus sib txawv zoo. Async functions yog npaj los ua lwm txoj hauv kev uas siv cov lus cog tseg.

Async/Await ua rau nws muaj peev xwm los npaj ua haujlwm nrog asynchronous code nyob rau hauv ib tug synchronous style.

Yog li, paub cov lus cog tseg ua rau nws yooj yim dua kom nkag siab cov ntsiab lus ntawm Async/Await.

syntax

Feem ntau nws muaj ob lo lus tseem ceeb: async thiab tos. Thawj lo lus hloov txoj haujlwm ua asynchronous. Cov haujlwm zoo li no tso cai rau kev siv tos. Hauv lwm qhov xwm txheej, siv qhov haujlwm no yuav ua rau muaj qhov yuam kev.

// With function declaration
 
async function myFn() {
  // await ...
}
 
// With arrow function
 
const myFn = async () => {
  // await ...
}
 
function myFn() {
  // await fn(); (Syntax Error since no async)
}
 

Async yog muab tso rau ntawm qhov pib ntawm kev tshaj tawm ua haujlwm, thiab nyob rau hauv rooj plaub ntawm kev ua haujlwm xub xub, nruab nrab ntawm "=" kos npe thiab cov kab lus.

Cov haujlwm no tuaj yeem muab tso rau hauv ib qho khoom raws li txoj hauv kev lossis siv hauv kev tshaj tawm hauv chav kawm.

// As an object's method
 
const obj = {
  async getName() {
    return fetch('https://www.example.com');
  }
}
 
// In a class
 
class Obj {
  async getResource() {
    return fetch('https://www.example.com');
  }
}

NB! Nws tsim nyog nco ntsoov tias chav tsev tsim thiab getters / setters tsis tuaj yeem ua asynchronous.

Semantics thiab execution rules

Async functions yeej zoo ib yam li cov qauv JS ua haujlwm, tab sis muaj kev zam.

Yog li, async functions ib txwm rov qab cog lus:

async function fn() {
  return 'hello';
}
fn().then(console.log)
// hello

Tshwj xeeb, fn rov qab txoj hlua nyob zoo. Zoo, txij li qhov no yog ib qho asynchronous muaj nuj nqi, txoj hlua tus nqi yog qhwv hauv cov lus cog tseg uas siv tus tsim.

Nov yog lwm txoj kev tsim yam tsis muaj Async:

function fn() {
  return Promise.resolve('hello');
}
 
fn().then(console.log);
// hello

Hauv qhov no, cov lus cog tseg raug xa rov qab "manually". Ib qho asynchronous muaj nuj nqi yog ib txwm qhwv hauv cov lus cog tseg tshiab.

Yog tias tus nqi xa rov qab yog qhov qub, qhov ua haujlwm async xa rov qab tus nqi los ntawm kev qhwv nws hauv kev cog lus. Yog tias tus nqi xa rov qab yog qhov khoom cog lus, nws qhov kev daws teeb meem raug xa rov qab rau hauv kev cog lus tshiab.

const p = Promise.resolve('hello')
p instanceof Promise;
// true
 
Promise.resolve(p) === p;
// true
 

Tab sis yuav ua li cas yog tias muaj qhov yuam kev hauv asynchronous muaj nuj nqi?

async function foo() {
  throw Error('bar');
}
 
foo().catch(console.log);

Yog tias nws tsis ua tiav, foo() yuav rov qab cog lus nrog kev tsis lees paub. Hauv qhov xwm txheej no, Promise.reject uas muaj qhov yuam kev yuav raug xa rov qab los ntawm Promise.resolve.

Async ua haujlwm ib txwm tso tawm cov lus cog tseg, tsis hais dab tsi rov qab los.

Asynchronous functions nres rau txhua qhov tos.

Await cuam tshuam cov lus qhia. Yog li, yog hais tias qhov kev qhia yog ib qho kev cog lus, qhov kev ua haujlwm async raug ncua mus txog thaum cov lus cog tseg tiav. Yog hais tias qhov kev qhia tsis yog kev cog lus, nws tau hloov dua siab tshiab rau kev cog lus ntawm Promise.resolve thiab tom qab ntawd ua tiav.

// utility function to cause delay
// and get random value
 
const delayAndGetRandom = (ms) => {
  return new Promise(resolve => setTimeout(
    () => {
      const val = Math.trunc(Math.random() * 100);
      resolve(val);
    }, ms
  ));
};
 
async function fn() {
  const a = await 9;
  const b = await delayAndGetRandom(1000);
  const c = await 5;
  await delayAndGetRandom(1000);
 
  return a + b * c;
}
 
// Execute fn
fn().then(console.log);

Thiab ntawm no yog cov lus piav qhia txog yuav ua li cas fn muaj nuj nqi ua haujlwm.

  • Tom qab hu nws, thawj kab yog hloov los ntawm const a = tos 9; hauv const a = await Promise.resolve(9);.
  • Tom qab siv Await, qhov kev ua haujlwm raug tshem tawm kom txog thaum tau txais nws tus nqi (hauv qhov xwm txheej tam sim no nws yog 9).
  • ncuaAndGetRandom(1000) ncua qhov kev ua tiav ntawm fn muaj nuj nqi kom txog thaum nws ua tiav nws tus kheej (tom qab 1 thib ob). Qhov no zoo nres fn muaj nuj nqi rau 1 thib ob.
  • ncuaAndGetRandom(1000) ntawm kev daws rov qab tus nqi random, uas yog muab rau qhov sib txawv b.
  • Zoo, rooj plaub uas muaj qhov sib txawv c zoo ib yam li rooj plaub uas muaj qhov sib txawv a. Tom qab ntawd, txhua yam nres rau ib pliag, tab sis tam sim no ncuaAndGetRandom(1000) rov qab tsis muaj dab tsi vim nws tsis tas yuav tsum tau ua.
  • Yog li ntawd, cov txiaj ntsig tau suav nrog cov qauv a + b * c. Cov txiaj ntsig tau muab qhwv rau hauv kev cog lus siv Promise.resolve thiab xa rov qab los ntawm kev ua haujlwm.

Cov kev ncua no tuaj yeem nco txog cov tshuab hluav taws xob hauv ES6, tab sis muaj qee yam rau nws koj vim li cas.

daws qhov teeb meem

Zoo, tam sim no cia saib cov kev daws teeb meem uas tau hais los saum toj no.

Lub finishMyTask muaj nuj nqi siv Await tos rau cov txiaj ntsig ntawm kev ua haujlwm xws li queryDatabase, sendEmail, logTaskInFile, thiab lwm yam. Yog tias koj piv cov tshuaj no nrog rau qhov uas tau cog lus tseg, qhov zoo sib xws yuav pom tseeb. Txawm li cas los xij, Async/Await version ua kom yooj yim rau tag nrho cov syntactic complexities. Nyob rau hauv rooj plaub no, tsis muaj coob tus callbacks thiab chains zoo li .then/.catch.

Ntawm no yog ib qho kev daws teeb meem nrog cov zis ntawm cov lej, muaj ob txoj kev xaiv.

const wait = (i, ms) => new Promise(resolve => setTimeout(() => resolve(i), ms));
 
// Implementation One (Using for-loop)
const printNumbers = () => new Promise((resolve) => {
  let pr = Promise.resolve(0);
  for (let i = 1; i <= 10; i += 1) {
    pr = pr.then((val) => {
      console.log(val);
      return wait(i, Math.random() * 1000);
    });
  }
  resolve(pr);
});
 
// Implementation Two (Using Recursion)
 
const printNumbersRecursive = () => {
  return Promise.resolve(0).then(function processNextPromise(i) {
 
    if (i === 10) {
      return undefined;
    }
 
    return wait(i, Math.random() * 1000).then((val) => {
      console.log(val);
      return processNextPromise(i + 1);
    });
  });
};

Thiab ntawm no yog kev daws teeb meem siv async functions.

async function printNumbersUsingAsync() {
  for (let i = 0; i < 10; i++) {
    await wait(i, Math.random() * 1000);
    console.log(i);
  }
}

Tuav yuam kev

Unhandled yuam kev yog qhwv hauv cov lus cog tseg tsis lees paub. Txawm li cas los xij, async functions tuaj yeem siv sim / ntes los daws cov teeb meem synchronously.

async function canRejectOrReturn() {
  // wait one second
  await new Promise(res => setTimeout(res, 1000));
 
// Reject with ~50% probability
  if (Math.random() > 0.5) {
    throw new Error('Sorry, number too big.')
  }
 
return 'perfect number';
}

canRejectOrReturn() yog ib qho kev ua haujlwm asynchronous uas ua tiav ("tus lej zoo meej") lossis ua tsis tiav nrog qhov yuam kev ("Thov txim, tus lej loj dhau").

async function foo() {
  try {
    await canRejectOrReturn();
  } catch (e) {
    return 'error caught';
  }
}

Txij li cov piv txwv saum toj no cia siab tias canRejectOrReturn ua kom tiav, nws tus kheej tsis ua haujlwm yuav ua rau kev ua tiav ntawm kev ntes thaiv. Raws li qhov tshwm sim, qhov ua haujlwm foo yuav xaus nrog qhov tsis tau hais tseg (thaum tsis muaj dab tsi rov qab los hauv kev sim thaiv) lossis nrog qhov yuam kev ntes. Raws li qhov tshwm sim, qhov haujlwm no yuav tsis poob vim qhov sim / ntes yuav ua haujlwm foo nws tus kheej.

Nov yog lwm qhov piv txwv:

async function foo() {
  try {
    return canRejectOrReturn();
  } catch (e) {
    return 'error caught';
  }
}

Nws yog ib qho tsim nyog them sai sai rau qhov tseeb tias hauv qhov piv txwv, canRejectOrReturn rov qab los ntawm foo. Foo nyob rau hauv cov ntaub ntawv no yog txiav nrog ib tug zoo meej tooj los yog xa rov qab qhov yuam kev ("Thov txim, tus lej loj dhau"). Lub catch block yuav tsis raug tua.

Qhov teeb meem yog tias foo rov qab cov lus cog tseg dhau los ntawm canRejectOrReturn. Yog li kev daws rau foo dhau los ua kev daws teeb meem rau canRejectOrReturn. Hauv qhov no, cov cai yuav muaj tsuas yog ob kab:

try {
    const promise = canRejectOrReturn();
    return promise;
}

Nov yog qhov tshwm sim yog tias koj siv tos thiab rov qab ua ke:

async function foo() {
  try {
    return await canRejectOrReturn();
  } catch (e) {
    return 'error caught';
  }
}

Hauv cov cai saum toj no, foo yuav tawm mus ua tiav nrog ob tus lej zoo meej thiab qhov yuam kev raug ntes. Yuav tsis muaj qhov tsis lees paub ntawm no. Tab sis foo yuav rov qab nrog canRejectOrReturn, tsis yog nrog undefined. Cia peb ua kom paub tseeb qhov no los ntawm kev tshem tawm qhov rov qab tuaj tos canRejectOrReturn() kab:

try {
    const value = await canRejectOrReturn();
    return value;
}
// …

Feem ntau yuam kev thiab pitfalls

Qee qhov xwm txheej, siv Async/Await tuaj yeem ua rau yuam kev.

Tsis nco qab tos

Qhov no tshwm sim ntau zaus - lo lus tseem ceeb tos tsis nco qab ua ntej cov lus cog tseg:

async function foo() {
  try {
    canRejectOrReturn();
  } catch (e) {
    return 'caught';
  }
}

Raws li koj tuaj yeem pom, tsis muaj kev tos lossis rov qab los ntawm cov cai. Yog li foo ib txwm tawm nrog undefined yam tsis muaj 1 thib ob ncua. Tiamsis tej lus cog tseg yuav ua tiav. Yog tias nws cuam tshuam qhov yuam kev lossis tsis lees paub, ces UnhandledPromiseRejectionWarning yuav raug hu.

Async Functions hauv Callbacks

Async functions feem ntau siv hauv .map lossis .filter li callbacks. Ib qho piv txwv yog fetchPublicReposCount(username) muaj nuj nqi, uas xa rov qab tus naj npawb ntawm qhib repositories ntawm GitHub. Cia peb hais tias muaj peb tus neeg siv nws qhov kev ntsuas peb xav tau. Nov yog txoj cai rau txoj haujlwm no:

const url = 'https://api.github.com/users';
 
// Utility fn to fetch repo counts
const fetchPublicReposCount = async (username) => {
  const response = await fetch(`${url}/${username}`);
  const json = await response.json();
  return json['public_repos'];
}

Peb xav tau ArfatSalman, octocat, norvig accounts. Hauv qhov no peb ua:

const users = [
  'ArfatSalman',
  'octocat',
  'norvig'
];
 
const counts = users.map(async username => {
  const count = await fetchPublicReposCount(username);
  return count;
});

Nws tsim nyog them nyiaj rau Await hauv .map callback. Cov suav ntawm no yog cov lus cog tseg, thiab .map yog qhov tsis qhia npe hu rov qab rau txhua tus neeg siv.

Kev siv ntau dhau ntawm tos

Cia peb coj tus lej no ua piv txwv:

async function fetchAllCounts(users) {
  const counts = [];
  for (let i = 0; i < users.length; i++) {
    const username = users[i];
    const count = await fetchPublicReposCount(username);
    counts.push(count);
  }
  return counts;
}

Ntawm no tus naj npawb repo tau muab tso rau hauv suav qhov sib txawv, ces tus lej no tau ntxiv rau cov suav array. Qhov teeb meem nrog cov cai yog kom txog thaum thawj tus neeg siv cov ntaub ntawv tuaj txog ntawm lub server, tag nrho cov neeg siv tom ntej yuav nyob hauv hom standby. Yog li, tsuas yog ib tus neeg siv tau ua tiav ntawm ib lub sijhawm.

Yog tias, piv txwv li, nws yuav siv li 300 ms los ua ib tus neeg siv, tom qab ntawd rau txhua tus neeg siv nws twb yog thib ob; lub sijhawm siv linearly nyob ntawm tus naj npawb ntawm cov neeg siv. Tab sis txij li thaum tau txais tus naj npawb ntawm repo tsis nyob ntawm ib leeg, cov txheej txheem tuaj yeem sib npaug. Qhov no yuav tsum tau ua haujlwm nrog .map thiab Promise.all:

async function fetchAllCounts(users) {
  const promises = users.map(async username => {
    const count = await fetchPublicReposCount(username);
    return count;
  });
  return Promise.all(promises);
}

Promise.all tau txais ib qho array ntawm cov lus cog tseg raws li cov tswv yim thiab xa rov qab cov lus cog tseg. Tom qab tag nrho, tom qab tag nrho cov lus cog tseg nyob rau hauv lub array tau ua tiav los yog nyob rau hauv thawj qhov kev tsis lees paub, ua tiav. Tej zaum nws yuav tshwm sim tias lawv txhua tus tsis pib tib lub sijhawm - txhawm rau kom ntseeg tau tias pib ib txhij, koj tuaj yeem siv p-map.

xaus

Async functions tau dhau los ua qhov tseem ceeb rau kev txhim kho. Zoo, rau kev hloov pauv ntawm async zog, koj yuav tsum siv Async Iterators. Tus tsim tawm JavaScript yuav tsum tau paub zoo hauv qhov no.

Skillbox pom zoo:

Tau qhov twg los: www.hab.com

Ntxiv ib saib