Jẹ ki a wo Async/Duro ni JavaScript ni lilo awọn apẹẹrẹ

Onkọwe ti nkan naa ṣe ayẹwo awọn apẹẹrẹ ti Async/Await ni JavaScript. Lapapọ, Async/Await jẹ ọna irọrun lati kọ koodu asynchronous. Ṣaaju ki ẹya ara ẹrọ yii to han, iru koodu ti kọ ni lilo awọn ipe ati awọn ileri. Onkọwe ti nkan atilẹba ṣafihan awọn anfani ti Async/Await nipa ṣiṣe ayẹwo awọn apẹẹrẹ pupọ.

A leti: fun gbogbo awọn oluka ti "Habr" - ẹdinwo ti 10 rubles nigbati o forukọsilẹ ni eyikeyi iṣẹ-ẹkọ Skillbox nipa lilo koodu ipolowo “Habr”.

Skillbox ṣe iṣeduro: Ẹkọ lori ayelujara ti ẹkọ "Olugbese Java".

callback

Ipe pada jẹ iṣẹ ti ipe rẹ ti daduro titilai. Ni iṣaaju, awọn ipe pada ni a lo ni awọn agbegbe ti koodu nibiti abajade ko le gba lẹsẹkẹsẹ.

Eyi ni apẹẹrẹ ti kika faili asynchronously ni Node.js:

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

Awọn iṣoro dide nigbati o nilo lati ṣe ọpọlọpọ awọn iṣẹ asynchronous ni ẹẹkan. Jẹ ki a foju inu wo oju iṣẹlẹ yii: a ṣe ibeere kan si data olumulo Arfat, o nilo lati ka aaye profaili_img_url rẹ ati ṣe igbasilẹ aworan kan lati olupin someserver.com.
Lẹhin igbasilẹ, a yi aworan pada si ọna kika miiran, fun apẹẹrẹ lati PNG si JPEG. Ti iyipada naa ba ṣaṣeyọri, a fi lẹta ranṣẹ si imeeli olumulo. Nigbamii ti, alaye nipa iṣẹlẹ naa ti wa ni titẹ sinu faili transformations.log, ti o nfihan ọjọ naa.

O tọ lati san ifojusi si agbekọja ti awọn ipe pada ati nọmba nla ti}) ni apakan ikẹhin ti koodu naa. O ni a npe ni Callback apaadi tabi jibiti ti Dumu.

Awọn aila-nfani ti ọna yii jẹ kedere:

  • Yi koodu jẹ soro lati ka.
  • O tun soro lati mu awọn aṣiṣe, eyiti o nigbagbogbo nyorisi didara koodu ti ko dara.

Lati yanju iṣoro yii, a ṣafikun awọn ileri si JavaScript. Wọn gba ọ laaye lati rọpo itẹ-ẹiyẹ ti o jinlẹ ti awọn ipe pada pẹlu ọrọ .lẹhinna.

Abala rere ti awọn ileri ni pe wọn jẹ ki koodu naa dara julọ kika, lati oke de isalẹ ju lati osi si otun. Sibẹsibẹ, awọn ileri tun ni awọn iṣoro wọn:

  • O nilo lati fi ọpọlọpọ .lẹhinna.
  • Dipo igbiyanju / apeja, a lo .catch lati mu gbogbo awọn aṣiṣe.
  • Ṣiṣẹ pẹlu awọn ileri pupọ laarin lupu kan kii ṣe rọrun nigbagbogbo ni awọn igba miiran, wọn diju koodu naa.

Eyi ni iṣoro kan ti yoo ṣe afihan itumọ aaye ti o kẹhin.

Ṣebi a ni fun lupu ti o tẹjade lẹsẹsẹ awọn nọmba lati 0 si 10 ni awọn aaye laileto (0–n iṣẹju-aaya). Lilo awọn ileri, o nilo lati yi lupu yii pada ki awọn nọmba ti wa ni titẹ ni ọna lati 0 si 10. Nitorina, ti o ba gba awọn aaya 6 lati tẹjade odo kan ati awọn aaya 2 lati tẹ ọkan, odo yẹ ki o wa ni titẹ akọkọ, lẹhinna kika fun titẹ ọkan yoo bẹrẹ.

Ati pe dajudaju, a ko lo Async/Await tabi .sort lati yanju iṣoro yii. Apeere ojutu ni opin.

Awọn iṣẹ Async

Awọn afikun awọn iṣẹ async ni ES2017 (ES8) jẹ ki o rọrun iṣẹ-ṣiṣe ti ṣiṣẹ pẹlu awọn ileri. Mo ṣe akiyesi pe awọn iṣẹ async ṣiṣẹ "lori oke" ti awọn ileri. Awọn iṣẹ wọnyi ko ṣe aṣoju awọn imọran oriṣiriṣi didara. Awọn iṣẹ Async jẹ ipinnu bi yiyan si koodu ti o nlo awọn ileri.

Async/Await jẹ ki o ṣee ṣe lati ṣeto iṣẹ pẹlu koodu asynchronous ni ara amuṣiṣẹpọ.

Nitorinaa, mimọ awọn ileri jẹ ki o rọrun lati ni oye awọn ipilẹ ti Async/Await.

Syntax

Ni deede o ni awọn koko-ọrọ meji: async ati duro. Ọrọ akọkọ sọ iṣẹ naa di asynchronous. Iru awọn iṣẹ gba awọn lilo ti await. Ni eyikeyi ọran miiran, lilo iṣẹ yii yoo ṣe aṣiṣe kan.

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

Async fi sii ni ibẹrẹ ti ikede iṣẹ, ati ninu ọran ti iṣẹ itọka, laarin ami “=” ati awọn akọmọ.

Awọn iṣẹ wọnyi le wa ni gbe sinu ohun kan bi awọn ọna tabi lo ninu ikede kilasi kan.

// 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! O tọ lati ranti pe awọn olupilẹṣẹ kilasi ati awọn getters/setters ko le jẹ asynchronous.

Awọn atunmọ ati awọn ofin ipaniyan

Awọn iṣẹ Async jẹ ipilẹ iru si awọn iṣẹ JS boṣewa, ṣugbọn awọn imukuro wa.

Nitorinaa, awọn iṣẹ async nigbagbogbo da awọn ileri pada:

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

Ni pataki, fn da okun pada hello. O dara, niwọn igba ti eyi jẹ iṣẹ asynchronous, iye okun ti wa ni we sinu ileri nipa lilo oluṣeto kan.

Eyi ni apẹrẹ yiyan laisi Async:

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

Ni idi eyi, ileri naa yoo pada "ọwọ". Iṣẹ asynchronous jẹ nigbagbogbo ti a we sinu ileri tuntun.

Ti iye ipadabọ ba jẹ alakoko, iṣẹ async da iye pada nipa fifẹ rẹ ni ileri kan. Ti iye ipadabọ jẹ nkan ileri, ipinnu rẹ yoo pada ni ileri tuntun.

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

Ṣugbọn kini yoo ṣẹlẹ ti aṣiṣe ba wa ninu iṣẹ asynchronous kan?

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

Ti ko ba ni ilọsiwaju, foo () yoo da ileri pada pẹlu ijusile. Ni ipo yii, Promise.reject ti o ni aṣiṣe yoo da pada dipo Promise.resolve.

Awọn iṣẹ Async ṣe agbejade ileri nigbagbogbo, laibikita ohun ti o pada.

Awọn iṣẹ Asynchronous da duro ni gbogbo idaduro.

Await ni ipa lori awọn ikosile. Nitorina, ti ikosile naa ba jẹ ileri, iṣẹ async ti daduro titi ti ileri yoo fi ṣẹ. Ti ikosile ko ba jẹ ileri, o ti yipada si ileri nipasẹ Promise.resolve ati lẹhinna pari.

// 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);

Ati pe eyi ni apejuwe bi iṣẹ fn ṣe n ṣiṣẹ.

  • Lẹhin pipe rẹ, ila akọkọ ti yipada lati const a = duro 9; ni const a = duro Promise.resolve (9);.
  • Lẹhin lilo Await, ipaniyan iṣẹ ti daduro titi di igba ti iye kan yoo gba (ni ipo lọwọlọwọ o jẹ 9).
  • delayAndGetRandom(1000) da duro ipaniyan ti iṣẹ fn titi yoo fi pari funrararẹ (lẹhin iṣẹju 1). Eyi ni imunadoko da iṣẹ fn duro fun iṣẹju 1.
  • delayAndGetRandom(1000) nipasẹ ipinnu pada a ID iye, eyi ti o ti wa ni sọtọ si oniyipada b.
  • O dara, ọran pẹlu oniyipada c jẹ iru si ọran pẹlu oniyipada a. Lẹhin iyẹn, ohun gbogbo duro fun iṣẹju kan, ṣugbọn ni bayi delayAndGetRandom(1000) ko da nkankan pada nitori ko nilo.
  • Bi abajade, a ṣe iṣiro awọn iye nipa lilo agbekalẹ a + b * c. Abajade ti a we sinu ileri nipa lilo Promise.resolve ati pada nipasẹ iṣẹ naa.

Awọn idaduro wọnyi le jẹ iranti ti awọn olupilẹṣẹ ni ES6, ṣugbọn nkankan wa si idi rẹ.

Yiyan iṣoro naa

O dara, ni bayi jẹ ki a wo ojuutu si iṣoro ti a mẹnuba loke.

Iṣẹ ipariMyTask naa nlo Await lati duro fun awọn abajade ti awọn iṣẹ bii ibeereDatabase, imeeli firanṣẹ, logTaskInFile, ati awọn omiiran. Ti o ba ṣe afiwe ojutu yii pẹlu eyiti a ti lo awọn ileri, awọn ibajọra yoo han gbangba. Sibẹsibẹ, ẹya Async/Await jẹ ki o rọrun pupọ gbogbo awọn idiju syntactic. Ni idi eyi, ko si nọmba nla ti awọn ipe ati awọn ẹwọn bi .lẹhinna / .catch.

Eyi ni ojutu kan pẹlu abajade awọn nọmba, awọn aṣayan meji wa.

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);
    });
  });
};

Ati pe eyi ni ojutu kan nipa lilo awọn iṣẹ async.

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

Ṣiṣe aṣiṣe

Awọn aṣiṣe ti a ko ṣakoso ni a we sinu ileri ti a kọ silẹ. Sibẹsibẹ, awọn iṣẹ async le lo igbiyanju/mu lati mu awọn aṣiṣe ṣiṣẹpọ.

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 () jẹ iṣẹ asynchronous ti boya ṣaṣeyọri (“nọmba pipe”) tabi kuna pẹlu aṣiṣe kan (“Mabinu, nọmba ti tobi ju”).

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

Niwọn bi apẹẹrẹ ti o wa loke nireti canRejectOrReturn lati ṣiṣẹ, ikuna tirẹ yoo ja si ipaniyan ti bulọọki apeja naa. Bi abajade, foo iṣẹ yoo pari pẹlu boya aisọye (nigbati ohunkohun ko ba pada ni idinaduro igbiyanju) tabi pẹlu aṣiṣe ti mu. Bi abajade, iṣẹ yii kii yoo kuna nitori igbiyanju / apeja yoo mu iṣẹ foo funrararẹ.

Eyi ni apẹẹrẹ miiran:

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

O tọ lati san ifojusi si otitọ pe ninu apẹẹrẹ, canRejectOrReturn ti pada lati foo. Foo ninu ọran yii boya fopin si pẹlu nọmba pipe tabi da Aṣiṣe pada (“Ma binu, nọmba ti tobi ju”). Awọn apeja Àkọsílẹ yoo ko wa ni executed.

Iṣoro naa ni pe foo da ileri ti o kọja lati canRejectOrReturn pada. Nitorina ojutu si foo di ojutu si canRejectOrReturn. Ni idi eyi, koodu naa yoo ni awọn laini meji nikan:

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

Eyi ni ohun ti o ṣẹlẹ ti o ba lo duro ati pada papọ:

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

Ninu koodu ti o wa loke, foo yoo jade ni aṣeyọri pẹlu nọmba pipe ati aṣiṣe ti o mu. Nibẹ ni yio je ko si refusals nibi. Ṣugbọn foo yoo pada pẹlu canRejectOrReturn, kii ṣe aisọye. Jẹ ki a rii daju eyi nipa yiyọ ipadabọ nduro canRejectOrReturn() laini:

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

Wọpọ asise ati awọn pitfalls

Ni awọn igba miiran, lilo Async/Await le ja si awọn aṣiṣe.

Igbagbe duro

Eyi n ṣẹlẹ ni igbagbogbo - Koko idaduro ti gbagbe ṣaaju ileri naa:

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

Bi o ti le rii, ko si idaduro tabi ipadabọ ninu koodu naa. Nitorina foo nigbagbogbo jade pẹlu aisọye laisi idaduro iṣẹju 1 kan. Ṣugbọn ileri yoo ṣẹ. Ti o ba gbejade aṣiṣe tabi ijusile, lẹhinna UnhandledPromiseRejectionWarning yoo pe.

Awọn iṣẹ Async ni Awọn ipe pada

Awọn iṣẹ Async jẹ igbagbogbo lo ni maapu tabi .filter bi awọn ipe pada. Apeere ni iṣẹ fetchPublicReposCount(orukọ olumulo), eyiti o da nọmba awọn ibi ipamọ ṣiṣi pada lori GitHub. Jẹ ki a sọ pe awọn olumulo mẹta wa ti awọn metiriki ti a nilo. Eyi ni koodu fun iṣẹ-ṣiṣe yii:

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'];
}

A nilo ArfatSalman, octocat, awọn akọọlẹ norvig. Ni idi eyi a ṣe:

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

O tọ lati san ifojusi si Duro ni .map callback. Nibi awọn iṣiro jẹ ọpọlọpọ awọn ileri, ati .map jẹ ipe ipe alailorukọ fun olumulo kọọkan pato.

Aṣeju dédé lilo ti dè

Jẹ ki a gba koodu yii gẹgẹbi apẹẹrẹ:

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;
}

Nibi nọmba repo ni a gbe sinu oniyipada kika, lẹhinna nọmba yii ni afikun si titobi awọn iṣiro. Iṣoro pẹlu koodu naa ni pe titi data olumulo akọkọ yoo de lati olupin, gbogbo awọn olumulo ti o tẹle yoo wa ni ipo imurasilẹ. Nitorinaa, olumulo kan ṣoṣo ni a ṣe ilana ni akoko kan.

Ti, fun apẹẹrẹ, o gba to 300 ms lati ṣe ilana olumulo kan, lẹhinna fun gbogbo awọn olumulo o ti jẹ iṣẹju-aaya kan; Ṣugbọn niwọn igba ti gbigba nọmba ti repo ko dale lori ara wọn, awọn ilana le jẹ afiwera. Eyi nilo ṣiṣe pẹlu .map ati Promise.all:

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

Promise.gbogbo gba ọpọlọpọ awọn ileri gẹgẹbi titẹ sii ati da ileri pada. Igbẹhin, lẹhin ti gbogbo awọn ileri ti o wa ninu akojọpọ ti pari tabi ni ijusile akọkọ, ti pari. O le ṣẹlẹ pe gbogbo wọn ko bẹrẹ ni akoko kanna - lati rii daju ibẹrẹ igbakana, o le lo p-map.

ipari

Awọn iṣẹ Async n di pataki pupọ si idagbasoke. O dara, fun lilo adaṣe ti awọn iṣẹ async, o yẹ ki o lo Async Iterators. Olùgbéejáde JavaScript yẹ ki o ni oye daradara ni eyi.

Skillbox ṣe iṣeduro:

orisun: www.habr.com

Fi ọrọìwòye kun