E nānā iā Async/Await ma JavaScript me ka hoʻohana ʻana i nā laʻana

Nānā ka mea kākau o ka ʻatikala i nā hiʻohiʻona o Async/Await ma JavaScript. ʻO ka holoʻokoʻa, ʻo Async/Await kahi ala kūpono e kākau ai i ka code asynchronous. Ma mua o ka puka ʻana o kēia hiʻohiʻona, ua kākau ʻia kēlā code me ka hoʻohana ʻana i nā callbacks a me nā ʻōlelo hoʻohiki. Hōʻike ka mea kākau o ka ʻatikala kumu i nā pono o Async/Await ma ka nānā ʻana i nā hiʻohiʻona like ʻole.

Hoʻomaopopo mākou iā ʻoe: no ka poʻe heluhelu a pau o "Habr" - kahi ho'ēmi o 10 rubles i ka wā e kākau inoa ai i kekahi papa Skillbox e hoʻohana ana i ka code promotional "Habr".

Manaʻo ʻo Skillbox: Papa hoʻonaʻauao pūnaewele "Ka mea hoʻomohala Java".

callback

ʻO ka Callback kahi hana i hoʻopaneʻe ʻia ke kelepona no ka manawa pau ʻole. Ma mua, ua hoʻohana ʻia nā kelepona i kēlā mau wahi o ke code kahi i hiki ʻole ke loaʻa koke ka hopena.

Eia kekahi laʻana o ka heluhelu asynchronously i kahi faila ma Node.js:

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

Piʻi ka pilikia inā pono ʻoe e hana i nā hana asynchronous i ka manawa hoʻokahi. E noʻonoʻo kākou i kēia hiʻohiʻona: ua noi ʻia i ka waihona mea hoʻohana Arfat, pono ʻoe e heluhelu i kāna kahua profile_img_url a hoʻoiho i kahi kiʻi mai ka server someserver.com.
Ma hope o ka hoʻoiho ʻana, hoʻololi mākou i ke kiʻi i kahi ʻano ʻē aʻe, no ka laʻana mai PNG a JPEG. Inā holomua ka hoʻololi ʻana, hoʻouna ʻia kahi leka i ka leka uila o ka mea hoʻohana. A laila, hoʻokomo ʻia ka ʻike e pili ana i ka hanana i ka faila transformations.log, e hōʻike ana i ka lā.

Pono e hoʻolohe i ka overlap o callbacks a me ka helu nui o }) ma ka hapa hope o ke code. Ua kapa ʻia ʻo Callback Hell a i ʻole Pyramid of Doom.

ʻIke ʻia nā hemahema o kēia ʻano:

  • He paʻakikī kēia code e heluhelu.
  • He mea paʻakikī hoʻi ka mālama ʻana i nā hewa, e alakaʻi pinepine ai i ka maikaʻi ʻole o ke code.

No ka hoʻoponopono ʻana i kēia pilikia, ua hoʻohui ʻia nā ʻōlelo hoʻohiki i JavaScript. Hāʻawi lākou iā ʻoe e hoʻololi i ka nesting hohonu o nā callbacks me ka huaʻōlelo .then.

ʻO ka hiʻohiʻona maikaʻi o nā ʻōlelo hoʻohiki, ʻoi aku ka maikaʻi o ka heluhelu ʻana i ke code, mai luna a lalo ma mua o ka hema a i ka ʻākau. Eia naʻe, loaʻa i nā ʻōlelo hoʻohiki ko lākou mau pilikia:

  • Pono ʻoe e hoʻohui i ka nui o .then.
  • Ma kahi o ka ho'āʻo/hopu, hoʻohana ʻia ʻo .catch e mālama i nā hewa āpau.
  • ʻAʻole maʻalahi ka hana ʻana me nā ʻōlelo hoʻohiki he nui i loko o ka loop hoʻokahi; i kekahi mau hihia, paʻakikī lākou i ke code.

Eia kekahi pilikia e hōʻike ana i ke ʻano o ka helu hope.

Inā paha he loop loop kā mākou e paʻi ana i ke kaʻina o nā helu mai ka 0 a hiki i ka 10 ma nā manawa āpau (0–n kekona). Me ka hoʻohana ʻana i nā ʻōlelo hoʻohiki, pono ʻoe e hoʻololi i kēia loop i paʻi ʻia nā helu ma ke kaʻina mai ka 0 a hiki i ka 10. No laila, inā 6 kekona e paʻi i kahi zero a me 2 kekona e paʻi i kahi, pono e paʻi mua ʻia ka zero, a laila e hoʻomaka ka helu ʻana no ka paʻi ʻana i ka mea.

A ʻoiaʻiʻo, ʻaʻole mākou e hoʻohana iā Async/Await a i ʻole .sort e hoʻoponopono i kēia pilikia. Aia kekahi laʻana hoʻonā ma ka hopena.

Nā hana Async

ʻO ka hoʻohui o nā hana async ma ES2017 (ES8) i maʻalahi i ka hana o ka hana me nā ʻōlelo hoʻohiki. ʻIke wau e hana ana nā hana async "ma luna" o nā ʻōlelo hoʻohiki. ʻAʻole hōʻike kēia mau hana i nā manaʻo like ʻole qualitatively. Hana ʻia nā hana Async ma ke ʻano he koho i ka code e hoʻohana ana i nā ʻōlelo hoʻohiki.

Hiki iā Async/Await ke hoʻonohonoho i ka hana me ka code asynchronous i kahi ʻano synchronous.

No laila, ʻo ka ʻike ʻana i nā ʻōlelo hoʻohiki e maʻalahi ka hoʻomaopopo ʻana i nā loina o Async/Await.

Ka Mooolelo O

ʻO ka maʻamau he mau huaʻōlelo ʻelua: async a kali. Hoʻololi ka huaʻōlelo mua i ka hana i asynchronous. Hāʻawi ia mau hana i ka hoʻohana ʻana i ka kali. Ma nā hihia ʻē aʻe, e hoʻohana ana kēia hana i kahi hewa.

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

Hoʻokomo ʻia ʻo Async ma ka hoʻomaka ʻana o ka hoʻolaha hana, a ma ke ʻano o kahi hana pua, ma waena o ka hōʻailona "=" a me nā pale.

Hiki ke hoʻokomo ʻia kēia mau hana i loko o kahi mea ma ke ʻano he ʻano hana a i ʻole hoʻohana ʻia i loko o kahi haʻi papa.

// 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! Pono e hoʻomanaʻo ʻaʻole hiki i nā mea kūkulu papa a me nā getters/setters ke asynchronous.

Semantics a me nā lula hoʻokō

Ua like like nā hana Async me nā hana JS maʻamau, akā aia nā ʻokoʻa.

No laila, hoʻihoʻi mau nā hana async i nā ʻōlelo hoʻohiki:

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

ʻOiaʻiʻo, hoʻihoʻi ʻo fn i ke kaula aloha. ʻAe, no ka mea he hana asynchronous kēia, ua kāʻei ʻia ka waiwai string i kahi ʻōlelo hoʻohiki me ka hoʻohana ʻana i kahi mea hana.

Eia kahi hoʻolālā ʻokoʻa me ka ʻole o Async:

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

I kēia hihia, hoʻihoʻi ʻia ka ʻōlelo hoʻohiki "manual". Hoʻopili mau ʻia kahi hana asynchronous i kahi ʻōlelo hoʻohiki hou.

Inā he primitive ka waiwai hoʻihoʻi, hoʻihoʻi ka hana async i ka waiwai ma ke kāʻei ʻana iā ia i kahi ʻōlelo hoʻohiki. Inā he mea hoʻohiki ka waiwai hoʻihoʻi, hoʻihoʻi ʻia kāna ʻōlelo hoʻoholo i kahi ʻōlelo hoʻohiki hou.

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

Akā he aha ka mea inā he hewa i loko o kahi hana asynchronous?

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

Inā ʻaʻole i hana ʻia, e hoʻihoʻi ka foo() i kahi ʻōlelo hoʻohiki me ka hōʻole. Ma kēia kūlana, e hoʻihoʻi ʻia ʻo Promise.reject me kahi hewa ma kahi o Promise.resolve.

Hoʻopuka mau nā hana Async i kahi ʻōlelo hoʻohiki, me ka nānā ʻole i ka mea i hoʻihoʻi ʻia.

Hoʻomaha nā hana Asynchronous i kēlā me kēia kali.

Hoʻopilikia ʻia nā ʻōlelo aʻoaʻo. No laila, inā he ʻōlelo hoʻohiki ka ʻōlelo, ua hoʻokuʻu ʻia ka hana async a hoʻokō ʻia ka ʻōlelo hoʻohiki. Inā ʻaʻole ia he ʻōlelo hoʻohiki, hoʻololi ʻia ia i ʻōlelo hoʻohiki ma o Promise.resolve a laila hoʻopau.

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

A eia ka wehewehe ʻana o ka hana o ka fn.

  • Ma hope o ke kāhea ʻana, ua hoʻololi ʻia ka laina mua mai const a = kali 9; in const a = kali Promise.resolve(9);.
  • Ma hope o ka hoʻohana ʻana iā Await, ua hoʻokuʻu ʻia ka hana a hiki i ka loaʻa ʻana o kāna waiwai (ma ke kūlana o kēia manawa ʻo 9).
  • Hoʻomaha ʻo delayAndGetRandom(1000) i ka hoʻokō ʻana i ka hana fn a hoʻopau iā ia iho (ma hope o 1 kekona). Hoʻopau pono kēia i ka hana fn no 1 kekona.
  • ʻO ka delayAndGetRandom(1000) ma o ka hoʻoholo e hoʻihoʻi i kahi waiwai kūʻokoʻa, a laila hāʻawi ʻia i ka hoʻololi b.
  • ʻAe, ua like ka hihia me ka variable c me ka hihia me ka variable a. Ma hope o kēlā, pau nā mea a pau no ke kekona, akā i kēia manawa ʻaʻole e hoʻihoʻi ʻo delayAndGetRandom(1000) no ka mea ʻaʻole koi ʻia.
  • ʻO ka hopena, helu ʻia nā waiwai me ka hoʻohana ʻana i ke ʻano a + b * c. Hoʻopili ʻia ka hopena i kahi ʻōlelo hoʻohiki me ka hoʻohana ʻana iā Promise.resolve a hoʻihoʻi ʻia e ka hana.

Hoʻomanaʻo paha kēia mau hoʻomaha i nā mea hana ma ES6, akā aia kekahi mea kou mau kumu.

Hoʻoholo i ka pilikia

ʻĀ, ʻānō e nānā kākou i ka hopena o ka pilikia i ʻōlelo ʻia ma luna.

Hoʻohana ka hana hopeMyTask iā Await e kali i nā hopena o nā hana e like me queryDatabase, sendEmail, logTaskInFile, a me nā mea ʻē aʻe. Inā hoʻohālikelike ʻoe i kēia hoʻonā me ka mea i hoʻohana ʻia ai nā ʻōlelo hoʻohiki, e ʻike ʻia nā mea like. Eia naʻe, maʻalahi loa ka mana Async/Await i nā paʻakikī syntactic āpau. I kēia hihia, ʻaʻohe helu nui o nā kelepona a me nā kaulahao e like me .then/.catch.

Eia kahi hoʻonā me ka puka ʻana o nā helu, ʻelua mau koho.

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

A eia kahi hoʻonā e hoʻohana ana i nā hana async.

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

Ke kuhi hewa

Hoʻopili ʻia nā kuhi hewa ʻole i ka ʻōlelo hoʻohiki i hōʻole ʻia. Eia nō naʻe, hiki i nā hana async ke hoʻohana i ka hoʻāʻo / hopu e hoʻoponopono i nā hewa i ka manawa like.

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() he hana asynchronous e kūleʻa ana ("helu kūpono") a i ʻole me ka hewa ("E kala mai, nui loa ka helu").

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

Ma muli o ka manaʻo o ka laʻana ma luna nei e hiki ke hoʻokō i ka hikiRejectOrReturn, ʻo kona hemahema ka hopena i ka hoʻokō ʻana i ka poloka hopu. ʻO ka hopena, e pau ka hana foo me ka ʻike ʻole ʻia (inā ʻaʻohe mea i hoʻihoʻi ʻia ma ka poloka hoʻāʻo) a i ʻole me kahi hewa i loaʻa. ʻO ka hopena, ʻaʻole e hāʻule kēia hana no ka mea e mālama ka hoʻāʻo/hopu i ka hana foo ponoʻī.

Eia kekahi laʻana:

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

Pono e hoʻolohe i ka ʻoiaʻiʻo i ka laʻana, hiki ke hoʻihoʻi ʻia mai ka foo. Hoʻopau ʻo Foo i kēia hihia me kahi helu kūpono a hoʻihoʻi paha i kahi Hapa ("E kala mai, nui loa ka helu"). ʻAʻole e hoʻokō ʻia ka poloka hopu.

ʻO ka pilikia ke hoʻihoʻi ʻo foo i ka ʻōlelo hoʻohiki i hāʻawi ʻia mai canRejectOrReturn. No laila, lilo ka hoʻonā i foo i mea hoʻonā e hiki keRejectOrReturn. I kēia hihia, ʻelua laina wale nō ke code:

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

Eia ka hopena inā hoʻohana ʻoe i ke kali a hoʻi pū:

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

Ma ke code ma luna, e puka maikaʻi ka foo me ka helu kūpono a me ka hewa i loaʻa. ʻAʻole e hōʻole ʻia ma ʻaneʻi. Akā e hoʻi ka foo me canRejectOrReturn, ʻaʻole me ka wehewehe ʻole. E hōʻoia i kēia ma ka wehe ʻana i ka laina hoʻihoʻi e kali canRejectOrReturn():

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

Nā hewa maʻamau a me nā pilikia

I kekahi mau hihia, hiki i ka hoʻohana ʻana iā Async/Await ke alakaʻi i nā hewa.

Poina ke kali

Hiki pinepine kēia - poina ka huaʻōlelo kali ma mua o ka ʻōlelo hoʻohiki:

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

E like me kāu e ʻike ai, ʻaʻohe kali a hoʻi ʻole i ke code. No laila, puka mau ka foo me undefined me ka lohi 1 kekona. Akā e hoʻokō ʻia ka ʻōlelo hoʻohiki. Inā he hewa a hōʻole paha, e kāhea ʻia ʻo UnhandledPromiseRejectionWarning.

Nā hana Async i nā Callbacks

Hoʻohana pinepine ʻia nā hana Async ma .map a i ʻole .filter e like me nā callbacks. ʻO kahi laʻana ka hana fetchPublicReposCount(inoa inoa), e hoʻihoʻi i ka helu o nā waihona wehe ma GitHub. E ʻōlelo mākou aia ʻekolu mea hoʻohana nona nā metric a mākou e pono ai. Eia ke code no kēia hana:

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

Pono mākou i nā moʻolelo ArfatSalman, octocat, norvig. I kēia hihia, hana mākou:

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

Pono e hoʻolohe iā Await ma ka .map callback. Eia ka helu ʻana i nā ʻōlelo hoʻohiki, a ʻo .map he kelepona inoa ʻole no kēlā me kēia mea hoʻohana i kuhikuhi ʻia.

Hoʻohana mau ʻia o ka kali

E lawe kākou i kēia code ma ke ʻano he laʻana:

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

Aia ka helu repo ma ka helu helu, a laila hoʻohui ʻia kēia helu i ka helu helu. ʻO ka pilikia me ke code a hiki i ka hōʻea ʻana o ka ʻikepili o ka mea hoʻohana mua mai ka kikowaena, e noho nā mea hoʻohana a pau ma ke ʻano standby. No laila, hoʻokahi wale nō mea hoʻohana e hana ʻia i ka manawa.

Inā, no ka laʻana, he 300 ms ke kaʻina hana hoʻokahi mea hoʻohana, a laila no nā mea hoʻohana a pau he kekona ia; ʻo ka manawa i hoʻohana ʻia ma ka laina laina e pili ana i ka helu o nā mea hoʻohana. Akā no ka loaʻa ʻana o ka helu repo ʻaʻole hilinaʻi i kekahi i kekahi, hiki ke hoʻohālikelike ʻia nā kaʻina hana. Pono kēia e hana me .map a me Promise.all:

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

Loaʻa iā Promise.all nā ʻōlelo hoʻohiki ma ke ʻano he hoʻokomo a hoʻihoʻi i kahi ʻōlelo hoʻohiki. ʻO ka hope, ma hope o ka pau ʻana o nā ʻōlelo hoʻohiki a pau a i ʻole ka hōʻole mua ʻana, ua pau. Malia paha ʻaʻole hoʻomaka lākou a pau i ka manawa like - i mea e hōʻoia ai i ka hoʻomaka like ʻana, hiki iā ʻoe ke hoʻohana i ka p-map.

hopena

Ke ulu nui nei nā hana Async no ka hoʻomohala ʻana. ʻAe, no ka hoʻohana ʻana i nā hana async, pono ʻoe e hoʻohana ʻO Async Iterators. Pono ka mea hoʻomohala JavaScript e ʻike i kēia.

Manaʻo ʻo Skillbox:

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka