Ake sibheke i-Async/Await ku-JavaScript sisebenzisa izibonelo

Umbhali wendatshana uhlola izibonelo ze-Async/Await ku-JavaScript. Sekukonke, i-Async/Await iyindlela elula yokubhala amakhodi asynchronous. Ngaphambi kokuba lesi sici sivele, ikhodi enjalo yayibhalwa kusetshenziswa ukufona emuva nezithembiso. Umbhali wendatshana yoqobo uveza izinzuzo ze-Async/Await ngokuhlaziya izibonelo ezahlukahlukene.

Siyakukhumbuza: kubo bonke abafundi be-"Habr" - isaphulelo sama-ruble angu-10 lapho ubhalisa kunoma yisiphi isifundo se-Skillbox usebenzisa ikhodi yephromoshini ethi "Habr".

I-Skillbox iyancoma: Isifundo se-inthanethi semfundo "Unjiniyela we-Java".

ukuphinda ukushayela

I-Callback umsebenzi okholi lwawo lubambezeleke unomphela. Ngaphambilini, ama-callbacks ayesetshenziswa kulezo zindawo zekhodi lapho umphumela wawungatholakali ngokushesha.

Nasi isibonelo sokufunda ifayela ngokulinganayo ku-Node.js:

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

Izinkinga ziyavela uma udinga ukwenza imisebenzi eminingana e-asynchronous ngesikhathi esisodwa. Ake sicabange ngalesi simo: isicelo senziwa kusizindalwazi sabasebenzisi be-Arfat, udinga ukufunda inkambu ye-profile_img_url bese ulanda isithombe kuseva ye-someserver.com.
Ngemva kokulanda, siguqula isithombe sibe kwenye ifomethi, isibonelo sisuka ku-PNG siye ku-JPEG. Uma ukuguqulwa kube yimpumelelo, incwadi ithunyelwa ku-imeyili yomsebenzisi. Okulandelayo, ulwazi mayelana nomcimbi lufakwa kufayela le-transformations.log, elibonisa usuku.

Kuyafaneleka ukunaka ukugqagqana kokufonelwa emuva kanye nenani elikhulu elithi }) engxenyeni yokugcina yekhodi. Ibizwa nge-Callback Hell noma iPyramid of Doom.

Ububi bale ndlela busobala:

  • Le khodi ifundeka kanzima.
  • Kunzima futhi ukuphatha amaphutha, okuvame ukuholela eqophelweni eliphansi lekhodi.

Ukuze kuxazululwe le nkinga, izithembiso zengezwe ku-JavaScript. Zikuvumela ukuthi umiselele ukubekela eceleni okujulile kwe-callbacks ngegama elithi .bese.

Isici esihle sezithembiso ukuthi zenza ikhodi ifundeke kangcono kakhulu, ukusuka phezulu kuye phansi kunokusuka kwesokunxele uye kwesokudla. Nokho, izithembiso nazo zinezinkinga zazo:

  • Udinga ukungeza okuningi .bese.
  • Esikhundleni sokuzama/ukubamba, i-.catch isetshenziselwa ukuphatha wonke amaphutha.
  • Ukusebenza ngezithembiso eziningi ngaphakathi kweluphu eyodwa akulula ngaso sonke isikhathi; kwezinye izimo, zenza ikhodi ibe nzima.

Nansi inkinga ezokhombisa incazelo yephuzu lokugcina.

Ake sithi sine-loop ephrinta ukulandelana kwezinombolo ukusuka ku-0 kuye ku-10 ngezikhathi ezithile (imizuzwana engu-0–n). Usebenzisa izithembiso, udinga ukushintsha le loop ukuze izinombolo ziphrintwe ngokulandelana ukusuka ku-0 kuye ku-10. Ngakho-ke, uma kuthatha imizuzwana engu-6 ukuphrinta u-ziro namasekhondi angu-2 ukuphrinta eyodwa, i-zero kufanele iphrintwe kuqala, bese emva kwalokho. ukubala wehle kokuphrinta eyodwa kuzoqala.

Futhi kunjalo, asisebenzisi i-Async/Await noma .sort ukuxazulula le nkinga. Isixazululo esiyisibonelo sisekupheleni.

Imisebenzi ye-Async

Ukwengezwa kwemisebenzi ye-async ku-ES2017 (ES8) kwenza umsebenzi wokusebenza ngezithembiso waba lula. Ngiyaqaphela ukuthi imisebenzi ye-async isebenza “phezu” kwezithembiso. Le misebenzi ayimeli imiqondo ehlukene ngekhwalithi. Imisebenzi ye-Async ihloswe njengenye indlela yekhodi esebenzisa izithembiso.

I-Async/Await yenza kube nokwenzeka ukuhlela umsebenzi ngekhodi engavumelaniyo ngesitayela esivumelanayo.

Ngakho-ke, ukwazi izithembiso kwenza kube lula ukuqonda izimiso ze-Async/Await.

I-syntax

Imvamisa iqukethe amagama angukhiye amabili: async futhi await. Igama lokuqala lishintsha umsebenzi ube ongavumelanisi. Imisebenzi enjalo ivumela ukusetshenziswa kokulinda. Kunoma isiphi esinye isimo, ukusebenzisa lo msebenzi kuzodala iphutha.

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

I-Async ishuthekwa ekuqaleni kwesimemezelo somsebenzi, futhi esimweni somsebenzi womcibisholo, phakathi kophawu “=" kanye nabakaki.

Le misebenzi ingafakwa entweni njengezindlela noma isetshenziswe kusimemezelo sekilasi.

// 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! Kuhle ukukhumbula ukuthi abakhi bekilasi kanye ne-getters/setter abakwazi ukuhambisana.

Imithetho ye-Semantics neyokwenza

Imisebenzi ye-Async ifana ngokuyisisekelo nemisebenzi ejwayelekile ye-JS, kodwa kukhona okuhlukile.

Ngakho, imisebenzi ye-async ihlala ibuyisela izithembiso:

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

Ngokukhethekile, i-fn ibuyisela iyunithi yezinhlamvu ethi sawubona. Nokho, njengoba lokhu kuwumsebenzi ongavumelanisi, inani lentambo ligoqwe ngesithembiso kusetshenziswa umakhi.

Nansi enye idizayini ngaphandle kwe-Async:

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

Kulokhu, isithembiso sibuyiselwa “ngesandla”. Umsebenzi we-asynchronous uhlala usongwe ngesithembiso esisha.

Uma inani lokubuyisela lingokokuqala, umsebenzi we-async ubuyisela inani ngokulisonga ngesithembiso. Uma inani lokubuyisela liyinto yesithembiso, ukulungiswa kwayo kubuyiselwa ngesithembiso esisha.

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

Kodwa kwenzekani uma kukhona iphutha ngaphakathi komsebenzi we-asynchronous?

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

Uma ingacutshungulwa, i-foo() izobuyisela isithembiso esinokwenqatshwa. Kulesi simo, i-Promise.reject equkethe iphutha izobuyiswa esikhundleni sokuthi Promise.resolve.

Imisebenzi ye-Async ihlala ikhipha isithembiso, kungakhathaliseki ukuthi yini ebuyiswa.

Imisebenzi ye-Asynchronous ima isikhashana kukho konke okulindile.

Ukulinda kuthinta izisho. Ngakho-ke, uma isisho siyisithembiso, umsebenzi we-async uyamiswa kuze kugcwaliseke isithembiso. Uma isisho singesona isithembiso, siguqulwa sibe isithembiso nge-Promise.resolve bese siyaqedwa.

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

Futhi nansi incazelo yokuthi umsebenzi we-fn usebenza kanjani.

  • Ngemva kokuyibiza, umugqa wokuqala uguqulwa usuka ku-const a = await 9; in const a = wait Promise.resolve(9);.
  • Ngemva kokusebenzisa i-Await, ukusebenza komsebenzi kuyamiswa kuze kube yilapho ithola inani layo (esimeni samanje ingu-9).
  • delayAndGetRandom(1000) imisa okwesikhashana ukuqaliswa komsebenzi we-fn ize iziqedele yona (emva kwesekhondi elingu-1). Lokhu kumisa ngempumelelo umsebenzi we-fn isekhondi elingu-1.
  • delayAndGetRandom(1000) nge-resolution ibuyisela inani elingahleliwe, elibe selabelwa kokuguquguqukayo okuthi b.
  • Nokho, icala elino-variable c lifana nekesi elino-variable a. Ngemva kwalokho, yonke into iyama umzuzwana, kodwa manje i- delayAndGetRandom(1000) ayibuyisi lutho ngoba ayidingeki.
  • Ngenxa yalokho, amanani abalwa kusetshenziswa ifomula a + b * c. Umphumela usongwe ngesithembiso kusetshenziswa i-Promise.resolve futhi ubuyiselwe umsebenzi.

Lokhu kumiswa kungase kufane nejeneretha ku-ES6, kodwa kukhona okuthile ngakho izizathu zakho.

Ukuxazulula inkinga

Awu, manje ake sibheke ikhambi lenkinga eshiwo ngenhla.

Umsebenzi we finishMyTask usebenzisa i-Await ukulinda imiphumela yemisebenzi efana ne-queryDatabase, sendEmail, logTaskInFile, nokunye. Uma uqhathanisa lesi sixazululo nalelo lapho kwasetshenziswa khona izithembiso, ukufana kuzoba sobala. Kodwa-ke, inguqulo ye-Async/Await yenza kube lula kakhulu zonke izinto eziyinkimbinkimbi zokwenziwa. Kulesi simo, alikho inani elikhulu lama-callback namaketango afana ne-.then/.catch.

Nasi isisombululo ngokuphuma kwezinombolo, kunezindlela ezimbili ongakhetha kuzo.

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

Futhi nasi isixazululo usebenzisa imisebenzi ye-async.

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

Iphutha ukucubungula

Amaphutha angaphathwanga asongwe ngesithembiso esinqatshiwe. Nokho, imisebenzi ye-async ingasebenzisa i-try/catch ukuze isingathe amaphutha ngokuvumelanisa.

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

I-canRejectOrReturn() iwumsebenzi ongavumelanisiwe ophumelela (“inombolo ephelele”) noma ehluleke ngephutha (“Uxolo, inombolo inkulu kakhulu”).

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

Njengoba isibonelo esingenhla silindele ukuthi i-canRejectOrReturn iqalise, ukwehluleka kwaso kuzoholela ekusetshenzisweni kwebhulokhi yokubamba. Njengomphumela, umsebenzi we-foo uzogcina ngokuthi okungachazwanga (uma kungabuyiswanga lutho kubhulokhi yokuzama) noma kubanjwe iphutha. Njengomphumela, lo msebenzi ngeke wehluleke ngoba ukuzama/ukubamba kuzophatha umsebenzi we-foo ngokwawo.

Nasi esinye isibonelo:

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

Kuyafaneleka ukunaka iqiniso lokuthi esibonelweni, i-canRejectOrReturn ibuyiselwa ku-foo. I-Foo kulokhu iphetha ngenombolo ephelele noma ibuyisele Iphutha (“Uxolo, inombolo inkulu kakhulu”). I-catch block ayisoze yasetshenziswa.

Inkinga ukuthi i-foo ibuyisela isithembiso esiphasiswe ku-canRejectOrReturn. Ngakho-ke isisombululo ku-foo siba yisixazululo se-canRejectOrReturn. Kulokhu, ikhodi izoba nemigqa emibili kuphela:

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

Nakhu okwenzekayo uma usebenzisa i-wait and return together:

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

Ekhodini engenhla, i-foo izophuma ngempumelelo kukho kokubili inombolo ephelele kanye nephutha elibanjwe. Ngeke kube khona ukwenqaba lapha. Kodwa i-foo izobuya ne-canRejectOrReturn, hhayi nge-undefined. Masiqinisekise lokhu ngokususa umugqa wokulinda we-canRejectOrReturn() wokubuya:

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

Amaphutha ajwayelekile kanye nezingibe

Kwezinye izimo, ukusebenzisa i-Async/Await kungaholela emaphutheni.

Ukhohlwe ukulinda

Lokhu kwenzeka kaningi - igama elingukhiye lokulinda liyakhohlwa ngaphambi kwesithembiso:

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

Njengoba ubona, akukho ukulinda noma ukubuya kukhodi. Ngakho-ke i-foo ihlezi iphuma ngokungachaziwe ngaphandle kokulibaziseka kwesekhondi elingu-1. Kodwa isithembiso sizogcwaliseka. Uma iphonsa iphutha noma ukwenqatshwa, kuzobe sekubizwa i-UnhandledPromiseRejectionWarning.

Imisebenzi ye-Async kuma-Callbacks

Imisebenzi ye-Async ivame ukusetshenziswa ku-.map noma .sihlungi njengama-callbacks. Isibonelo umsebenzi we-fetchPublicReposCount(igama lomsebenzisi), obuyisela inani lamakhosombe avuliwe ku-GitHub. Ake sithi kukhona abasebenzisi abathathu esiwadingayo amamethrikhi abo. Nansi ikhodi yalo msebenzi:

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

Sidinga ama-akhawunti we-ArfatSalman, i-octocat, ama-norvig. Kulokhu senza:

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

Kuyafaneleka ukunaka okuthi Linda ku-callback ye-.map. Lapha ukubala kuwuxhaxha lwezithembiso, futhi .map iwukuphinda ushayele ngokungaziwa kumsebenzisi ngamunye obaluliwe.

Ukusetshenziswa okuhambisanayo ngokweqile kokulinda

Ake sithathe le khodi njengesibonelo:

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

Lapha inombolo ye-repo ibekwe ekuguquguqukeni kokubala, bese le nombolo yengezwa ohlwini lokubala. Inkinga ngekhodi ukuthi kuze kube yilapho idatha yomsebenzisi wokuqala ifika ivela kuseva, bonke abasebenzisi abalandelayo bazoba kumodi yokulinda. Ngakho, umsebenzisi oyedwa kuphela ocutshungulwayo ngesikhathi.

Uma, ngokwesibonelo, kuthatha cishe u-300 ms ukucubungula umsebenzisi oyedwa, kuzosho ukuthi kubo bonke abasebenzisi sekuvele kuyisekhondi; isikhathi esichithwa ngokomugqa sincike enanini labasebenzisi. Kodwa njengoba ukuthola inombolo ye-repo akuncikile komunye nomunye, izinqubo zingafaniswa. Lokhu kudinga ukusebenza nge-.map kanye ne-Promise.all:

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

I-Promise.konke ithola uxhaxha lwezithembiso njengokufaka futhi ibuyisela isithembiso. Okwakamuva, ngemva kokuba zonke izithembiso ezikulolu chungechunge seziqediwe noma ekunqatshweni kokuqala, seziqediwe. Kungenzeka ukuthi zonke zingaqali ngesikhathi esisodwa - ukuze uqinisekise ukuqala kanyekanye, ungasebenzisa i-p-map.

isiphetho

Imisebenzi ye-Async iya ngokuya ibalulekile ekuthuthukisweni. Yebo, ngokusetshenziswa okuguquguqukayo kwemisebenzi ye-async, kufanele usebenzise I-Async Iterators. Umthuthukisi weJavaScript kufanele akwazi kahle lokhu.

I-Skillbox iyancoma:

Source: www.habr.com

Engeza amazwana