Intueamur Async / Exspecta in JavaScript usus exempla

Auctor articuli exempla Async/Await in JavaScript. Super, Async/Exspecta est opportuna via ad scribendum asynchronum codicem. Antequam haec factura apparebat, talis codice adhibitis callbacks pollicitationibusque scribebatur. Articuli originalis auctor ostendit commoda Async/Exspectate varia exempla resolvendo.

admonemus; omnibus legentibus "Habr" - discount 10 rublorum cum scribendo in quavis Skillbox utens "Habr" codice promotivo.

Skillbox commendat: Educational online course "Java elit".

callback

Callback est functio cuius vocatio in infinitum differtur. Antea callbacks in illis locis codicis adhibiti sunt ubi statim exitum obtineri non potuit.

Exemplum est hic asynchrone lima in Node.js legentis:

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

Problemata oriuntur cum pluribus simul operationibus asynchronis opus facere oportet. Hanc missionem cogitemus: petitio ad datorum usoris Arfat usoris facta, debes suum profile_img_url campum legere et imaginem e servo someserver.com deponi.
Post demptionem imaginem in aliam formam convertimus, exempli gratia ab PNG ad JPEG. Si conversio valuit, epistula ad inscriptionem usoris mittitur. Deinde, informationes de eventu in transformationes.log fasciculi inierunt, indicato tempus.

Operae pretium est in aliudquam callbacks et numerum }) in ultima codicis parte observare. Vocatur Callback Hell vel Pyramid Doom.

Incommoda huius methodi aperta sunt;

  • Difficile est hunc codicem legere.
  • Etiam difficile est errores tractare, qui saepe ad pauperem codicem qualitatem ducit.

Ad hanc quaestionem solvendam, promissiones JavaScript adiectae sunt. Altum nidificationem callbacks cum verbo .thenis reponere permittunt.

Promissionum aspectus affirmativus est quod codicem multo melius legabilem reddunt, a summo ad imum quam a sinistro ad dextrum. Sed promissiones etiam suas habent quaestiones;

  • Multum debes addere .then.
  • Instead of try/apprehendo, .capere adhibetur ad omnes errores tractandos.
  • Multiplici promissione in una ansa operari non semper convenit: in quibusdam codicem inpediunt.

Hic quaestio est quae sensum ultimi puncti ostendet.

Ponamus habere pro loop qui procer seriem numerorum ab 0 ad 10 intervallis temere (0-n secundis). Promissionibus utens, debes hanc ansam mutare ut numeri in ordine impressi sint ab 0 ad 10. Itaque, si sex secundis sumit ut nulla ac 6 secundis imprimendi unum imprimat, nulla prius imprimi debet, ac deinde. in countdown ad imprimendum alter incipiet.

Et sane non utimur Async/Expecta vel .sore ad solvendam hanc quaestionem. Exemplum est in fine.

Async munera

Additio async functionum in ES2017 (ES8) simpliciorem munus promissionibus operandi. Adnoto async functiones promissionum "super" operari. Hae functiones notiones diversae qualitatem non repraesentant. Munera Async destinantur ut alterutrum in codice qui promissis utitur.

Async/Expectate efficit ut opus cum asynchrono codice in synchrono stilo ordinare possit.

Sic promissiones cognoscens faciliorem facit principia Async/Expectate.

Syntax

Communiter consistit in duobus keywords: async et exspectantibus. Primum verbum munus in asynchronum vertit. Talia munera usum expecto permittunt. In alio casu hoc munus errorem generabit.

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

Async inseritur in principio functionis declarationis, et in casu functionis sagittae, inter " " signum et parenthesin."

Hae functiones in obiecto tamquam methodo poni possunt vel declaratione classis adhibita.

// 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! Memoria dignum est quod genus constructores et getters/setters asynchronos esse non possunt.

Semantics et praecepta supplicium

Munera Async basically similia sunt functionibus mensurae JS, sed exceptiones sunt.

Sic munera async promissiones semper reddunt;

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

In specie, fn chorda salve redit. Bene, cum asynchronum hoc munus sit, chorda valor promissionis fabricatoris involvitur.

Hic sine consilio alterius Async:

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

Hoc in casu, promissio "manualiter" redditur. Munus asynchronum semper nova promissione involvit.

Si reditus valorem primitivum est, munus async in promissione redit valorem involvendo. Si reditus pretii est, promissio obiecto, in nova promissione eius resolutio redditur.

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

Sed quid accidit si asynchrono munere error intus est?

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

Si non discursum est, foo promissio reddet cum rejectione. In hoc statu, Promise.reject continens errorem in loco Promise.resolve reddetur.

Async munera semper output promissum cuiuscumque redditur.

Munera asynchrona morantur in omni exspectatione.

Hxc affectat locutiones. Si ergo dictio est promissio, suspenditur munus async donec promissio impleatur. Si expressio non est promissio, convertitur ad promissionem per Promise.resolvere ac deinde peractam.

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

Atque hic est descriptio quomodo fn functione operatur.

  • Post eam vocatam, prima linea convertitur ex const a = expecto 9; in const a = expectare Promise.resolve(9);
  • Post usus Exspecta, munus exsecutionis suspenditur donec suum valorem obtineat (in praesenti situ 9).
  • delayAndGetRandom(1000) desistit exsecutio functionis fn donec se perficiat (post 1 secundum). Hoc munus efficaciter sistit fn pro 1 secundo.
  • delayAndGetRandom(1000) per propositum redit valorem temere, qui deinde varius b assignatus est.
  • Ita se habet cum c variabili simile se habet cum variabili a. Post haec omnia secundo subsistunt, nunc autem cunctatio AndGetRandom(1000) nihil redit quia non requiritur.
  • Quam ob rem, valores computantur formulam a + b* c. Effectus involvitur promissioni utens Promise.resolvere et remitti munere.

Hae pausulae simile generantium in ES6 esse possunt, sed aliquid est ei rationes tuas.

Solvendo problema

Iam nunc inspiciamus solutionem problematis supra memorati.

Munus metamMyTask utitur Exspecta ut eventus operationum expectet ut queryDatabase, sendEmail, logTaskInFile, et aliis. Si hanc solutionem compares cum eo in quo promissiones adhibitae sunt, similitudines in promptu erunt. Nihilominus, Async/Exspecta versio valde simplices omnes complexiones syntacticae. In hoc casu non est numerus callbacks et catenulae sicut .then/.captivae.

Solutio hic est cum numerorum output, duo bene.

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

Et hic est solutio functionum asyncturae.

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

Error processui

Errore non tractato involvitur rejecta promissio. Tamen, async functiones uti possunt experiri/capere ad errores synchrone tractandos.

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() munus asynchronum est quod vel succedit ("numerus perfectus") vel errore deficit ("Ignosce, numerus nimis magnus").

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

Cum exemplum superius expectat canRejectOrReturn ad exsequendum, suum defectum evenit in executione capturae scandali. Quam ob rem munus foo aut indefinitum (cum nihil in scandalum attentando redditur) aut errore captus erit. Quo fit, hoc munus non deficiet quia experimentum/captura munus ipsum foo tractabit.

Ecce aliud exemplum.

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

Operae pretium est quod in exemplo canRejectOrReturn redditur a foo. Foo in hoc casu vel cum numero perfecto terminatur vel errorem reddit (Β«Ignosce nimis magnum numerumΒ»). Captura scandalum numquam supplicium est.

Problema est quod foo repromissio reddita ex canRejectOrReturn. Sic solutio foo fit solutio ad canRejectOrReturn. Hoc in casu, in codice duabus tantum lineis constabit;

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

Hic id agitur, si simul uteris expectare et redire;

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

In codice superiore, foo feliciter cum perfecto numero et errore captus est. Nullae negationis hic erunt. Sed foo cum canRejectOrReturn redibit, non cum indefinito. Hoc certam faciamus subducto exspectatione reditus canRejectOrReturn() lineam:

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

Communia errata et foveae

In quibusdam casibus utens Async/Expectare potest errores ducere.

oblitus expectamus

Hoc saepius accidit - exspectatio keyword oblivioni tradita est ante promissionem:

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

Ut videre potes, nulla est exspectatio nec reditio in codice. Ergo foo semper sine fine secunda mora exit. Sed promissio implebitur. Si errorem vel reiectionem eiecerit, UnhandledPromiseRejection Warning vocabitur.

Async functiones in Callbacks

Munera Async saepius adhibentur in .map vel .filter sicut callbacks. Exemplum est functionis publicaeReposCount(usoris) quae numerum repositorium apertum in GitHub refert. Dicamus tres esse utentes quibus metricis opus est. Hic est signum huius operis:

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

Opus ArfatSalman, octocat, norvig rationum. In hoc casu facimus;

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

Operae pretium est ut Exspectate in callback .map. Hic numerat numerus promissionum, et .map est callback anonymi pro usoribus singulis definitis.

Nimis constans usus exspectationis

Hoc signum in exemplum sumamus:

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

Hic numerus in numero variabili in narratione ponitur, ergo hic numerus comitibus ordinatis additur. Difficultas in codice est quia donec primi usoris notitia e servo pervenerit, omnes posteriores notores in modo standi erunt. Ita unum tantum tempus usor discurrit.

Si exempli gratia, circiter 300 ms ad unum utentem processum, omnibus utentibus iam est alterum: tempus linearly dependet a numero utentium. Sed quia obtinens numerus repo non dependet ab invicem, possunt processus paralleli. Hoc opus cum .map et Promise.all requirit:

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

Promissio. Omnis ordinata promissiones accipit sicut input et promissionem reddit. Is, postquam omnia promissiones in ordine peregit, vel in prima reiectione absolvitur. Fieri potest ut non omnes simul incipiant - ut simultaneum exordium, p-mappa uti possis.

conclusio,

Async munera magis magisque momenti ad progressionem fiunt. Bene, ad usum adaptivam async munerum, uti debes Async Iterators. Elit JavaScript bene callet in hac.

Skillbox commendat:

Source: www.habr.com