ಉದಾಹರಣೆಗಳನ್ನು ಬಳಸಿಕೊಂಡು JavaScript ನಲ್ಲಿ Async/Await ಅನ್ನು ನೋಡೋಣ

ಲೇಖನದ ಲೇಖಕರು JavaScript ನಲ್ಲಿ Async/Await ನ ಉದಾಹರಣೆಗಳನ್ನು ಪರಿಶೀಲಿಸುತ್ತಾರೆ. ಒಟ್ಟಾರೆಯಾಗಿ, ಅಸಮಕಾಲಿಕ ಕೋಡ್ ಬರೆಯಲು Async/Await ಒಂದು ಅನುಕೂಲಕರ ಮಾರ್ಗವಾಗಿದೆ. ಈ ವೈಶಿಷ್ಟ್ಯವು ಕಾಣಿಸಿಕೊಳ್ಳುವ ಮೊದಲು, ಅಂತಹ ಕೋಡ್ ಅನ್ನು ಕಾಲ್ಬ್ಯಾಕ್ ಮತ್ತು ಭರವಸೆಗಳನ್ನು ಬಳಸಿ ಬರೆಯಲಾಗಿದೆ. ಮೂಲ ಲೇಖನದ ಲೇಖಕರು ವಿವಿಧ ಉದಾಹರಣೆಗಳನ್ನು ವಿಶ್ಲೇಷಿಸುವ ಮೂಲಕ Async/Await ನ ಅನುಕೂಲಗಳನ್ನು ಬಹಿರಂಗಪಡಿಸುತ್ತಾರೆ.

ನಾವು ನೆನಪಿಸುತ್ತೇವೆ: ಎಲ್ಲಾ Habr ಓದುಗರಿಗೆ - Habr ಪ್ರೊಮೊ ಕೋಡ್ ಬಳಸಿಕೊಂಡು ಯಾವುದೇ ಸ್ಕಿಲ್‌ಬಾಕ್ಸ್ ಕೋರ್ಸ್‌ಗೆ ದಾಖಲಾಗುವಾಗ 10 ರೂಬಲ್ ರಿಯಾಯಿತಿ.

ಸ್ಕಿಲ್‌ಬಾಕ್ಸ್ ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ: ಶೈಕ್ಷಣಿಕ ಆನ್‌ಲೈನ್ ಕೋರ್ಸ್ "ಜಾವಾ ಡೆವಲಪರ್".

ಕಾಲ್ಬ್ಯಾಕ್

ಕಾಲ್‌ಬ್ಯಾಕ್ ಒಂದು ಕಾರ್ಯವಾಗಿದ್ದು, ಅವರ ಕರೆಯು ಅನಿರ್ದಿಷ್ಟವಾಗಿ ವಿಳಂಬವಾಗುತ್ತದೆ. ಹಿಂದೆ, ಫಲಿತಾಂಶವನ್ನು ತಕ್ಷಣವೇ ಪಡೆಯಲಾಗದ ಕೋಡ್‌ನ ಕ್ಷೇತ್ರಗಳಲ್ಲಿ ಕಾಲ್‌ಬ್ಯಾಕ್‌ಗಳನ್ನು ಬಳಸಲಾಗುತ್ತಿತ್ತು.

Node.js ನಲ್ಲಿ ಫೈಲ್ ಅನ್ನು ಅಸಮಕಾಲಿಕವಾಗಿ ಓದುವ ಉದಾಹರಣೆ ಇಲ್ಲಿದೆ:

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

ನೀವು ಏಕಕಾಲದಲ್ಲಿ ಹಲವಾರು ಅಸಮಕಾಲಿಕ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ನಿರ್ವಹಿಸಬೇಕಾದಾಗ ತೊಂದರೆಗಳು ಉಂಟಾಗುತ್ತವೆ. ಈ ಸನ್ನಿವೇಶವನ್ನು ಊಹಿಸೋಣ: Arfat ಬಳಕೆದಾರ ಡೇಟಾಬೇಸ್‌ಗೆ ವಿನಂತಿಯನ್ನು ಮಾಡಲಾಗಿದೆ, ನೀವು ಅದರ profile_img_url ಕ್ಷೇತ್ರವನ್ನು ಓದಬೇಕು ಮತ್ತು someserver.com ಸರ್ವರ್‌ನಿಂದ ಚಿತ್ರವನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.
ಡೌನ್‌ಲೋಡ್ ಮಾಡಿದ ನಂತರ, ನಾವು ಚಿತ್ರವನ್ನು ಮತ್ತೊಂದು ಸ್ವರೂಪಕ್ಕೆ ಪರಿವರ್ತಿಸುತ್ತೇವೆ, ಉದಾಹರಣೆಗೆ PNG ನಿಂದ JPEG ಗೆ. ಪರಿವರ್ತನೆ ಯಶಸ್ವಿಯಾದರೆ, ಬಳಕೆದಾರರ ಇಮೇಲ್‌ಗೆ ಪತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗುತ್ತದೆ. ಮುಂದೆ, ಈವೆಂಟ್ ಬಗ್ಗೆ ಮಾಹಿತಿಯನ್ನು ಟ್ರಾನ್ಸ್ಫಾರ್ಮೇಷನ್ಸ್.ಲಾಗ್ ಫೈಲ್ನಲ್ಲಿ ನಮೂದಿಸಲಾಗಿದೆ, ಇದು ದಿನಾಂಕವನ್ನು ಸೂಚಿಸುತ್ತದೆ.

ಕೋಡ್‌ನ ಅಂತಿಮ ಭಾಗದಲ್ಲಿ ಕಾಲ್‌ಬ್ಯಾಕ್‌ಗಳ ಅತಿಕ್ರಮಣ ಮತ್ತು ದೊಡ್ಡ ಸಂಖ್ಯೆಯ }) ಗೆ ಗಮನ ಕೊಡುವುದು ಯೋಗ್ಯವಾಗಿದೆ. ಇದನ್ನು ಕಾಲ್ಬ್ಯಾಕ್ ಹೆಲ್ ಅಥವಾ ಪಿರಮಿಡ್ ಆಫ್ ಡೂಮ್ ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ.

ಈ ವಿಧಾನದ ಅನಾನುಕೂಲಗಳು ಸ್ಪಷ್ಟವಾಗಿವೆ:

  • ಈ ಕೋಡ್ ಓದಲು ಕಷ್ಟ.
  • ದೋಷಗಳನ್ನು ನಿಭಾಯಿಸಲು ಸಹ ಕಷ್ಟವಾಗುತ್ತದೆ, ಇದು ಸಾಮಾನ್ಯವಾಗಿ ಕಳಪೆ ಕೋಡ್ ಗುಣಮಟ್ಟಕ್ಕೆ ಕಾರಣವಾಗುತ್ತದೆ.

ಈ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಲು, ಭರವಸೆಗಳನ್ನು JavaScript ಗೆ ಸೇರಿಸಲಾಯಿತು. ಕಾಲ್‌ಬ್ಯಾಕ್‌ಗಳ ಆಳವಾದ ಗೂಡುಗಳನ್ನು .ನಂತರ ಎಂಬ ಪದದೊಂದಿಗೆ ಬದಲಾಯಿಸಲು ಅವು ನಿಮಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತವೆ.

ಭರವಸೆಗಳ ಧನಾತ್ಮಕ ಅಂಶವೆಂದರೆ ಅವರು ಕೋಡ್ ಅನ್ನು ಎಡದಿಂದ ಬಲಕ್ಕೆ ಬದಲಾಗಿ ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಹೆಚ್ಚು ಉತ್ತಮವಾಗಿ ಓದುವಂತೆ ಮಾಡುತ್ತದೆ. ಆದಾಗ್ಯೂ, ಭರವಸೆಗಳು ತಮ್ಮ ಸಮಸ್ಯೆಗಳನ್ನು ಹೊಂದಿವೆ:

  • ನಂತರ ನೀವು ಬಹಳಷ್ಟು ಸೇರಿಸುವ ಅಗತ್ಯವಿದೆ.
  • ಪ್ರಯತ್ನಿಸಿ/ಕ್ಯಾಚ್ ಬದಲಿಗೆ, ಎಲ್ಲಾ ದೋಷಗಳನ್ನು ನಿರ್ವಹಿಸಲು .catch ಅನ್ನು ಬಳಸಲಾಗುತ್ತದೆ.
  • ಒಂದು ಲೂಪ್ನಲ್ಲಿ ಬಹು ಭರವಸೆಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವುದು ಯಾವಾಗಲೂ ಅನುಕೂಲಕರವಾಗಿರುವುದಿಲ್ಲ; ಕೆಲವು ಸಂದರ್ಭಗಳಲ್ಲಿ, ಅವರು ಕೋಡ್ ಅನ್ನು ಸಂಕೀರ್ಣಗೊಳಿಸುತ್ತಾರೆ.

ಕೊನೆಯ ಅಂಶದ ಅರ್ಥವನ್ನು ತೋರಿಸುವ ಸಮಸ್ಯೆ ಇಲ್ಲಿದೆ.

ಯಾದೃಚ್ಛಿಕ ಮಧ್ಯಂತರಗಳಲ್ಲಿ (0-n ಸೆಕೆಂಡುಗಳು) 10 ರಿಂದ 0 ರವರೆಗಿನ ಸಂಖ್ಯೆಗಳ ಅನುಕ್ರಮವನ್ನು ಮುದ್ರಿಸುವ ಫಾರ್ ಲೂಪ್ ಅನ್ನು ನಾವು ಹೊಂದಿದ್ದೇವೆ ಎಂದು ಭಾವಿಸೋಣ. ಭರವಸೆಗಳನ್ನು ಬಳಸಿ, ನೀವು ಈ ಲೂಪ್ ಅನ್ನು ಬದಲಾಯಿಸಬೇಕಾಗಿದೆ ಆದ್ದರಿಂದ ಸಂಖ್ಯೆಗಳನ್ನು 0 ರಿಂದ 10 ರವರೆಗೆ ಅನುಕ್ರಮವಾಗಿ ಮುದ್ರಿಸಲಾಗುತ್ತದೆ. ಆದ್ದರಿಂದ, ಶೂನ್ಯವನ್ನು ಮುದ್ರಿಸಲು 6 ಸೆಕೆಂಡುಗಳು ಮತ್ತು ಒಂದನ್ನು ಮುದ್ರಿಸಲು 2 ಸೆಕೆಂಡುಗಳು ತೆಗೆದುಕೊಂಡರೆ, ಶೂನ್ಯವನ್ನು ಮೊದಲು ಮುದ್ರಿಸಬೇಕು, ತದನಂತರ ಒಂದನ್ನು ಮುದ್ರಿಸಲು ಕೌಂಟ್‌ಡೌನ್ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ.

ಮತ್ತು ಸಹಜವಾಗಿ, ಈ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಲು ನಾವು Async/Await ಅಥವಾ .sort ಅನ್ನು ಬಳಸುವುದಿಲ್ಲ. ಒಂದು ಉದಾಹರಣೆ ಪರಿಹಾರವು ಕೊನೆಯಲ್ಲಿದೆ.

ಅಸಿಂಕ್ ಕಾರ್ಯಗಳು

ES2017 (ES8) ನಲ್ಲಿ ಅಸಿಂಕ್ ಕಾರ್ಯಗಳ ಸೇರ್ಪಡೆಯು ಭರವಸೆಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವ ಕಾರ್ಯವನ್ನು ಸರಳಗೊಳಿಸಿದೆ. ಅಸಿಂಕ್ ಕಾರ್ಯಗಳು ಭರವಸೆಗಳ "ಮೇಲ್ಭಾಗದಲ್ಲಿ" ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ ಎಂದು ನಾನು ಗಮನಿಸುತ್ತೇನೆ. ಈ ಕಾರ್ಯಗಳು ಗುಣಾತ್ಮಕವಾಗಿ ವಿಭಿನ್ನ ಪರಿಕಲ್ಪನೆಗಳನ್ನು ಪ್ರತಿನಿಧಿಸುವುದಿಲ್ಲ. Async ಕಾರ್ಯಗಳನ್ನು ಭರವಸೆಗಳನ್ನು ಬಳಸುವ ಕೋಡ್‌ಗೆ ಪರ್ಯಾಯವಾಗಿ ಉದ್ದೇಶಿಸಲಾಗಿದೆ.

Async/Await ಸಿಂಕ್ರೊನಸ್ ಶೈಲಿಯಲ್ಲಿ ಅಸಮಕಾಲಿಕ ಕೋಡ್‌ನೊಂದಿಗೆ ಕೆಲಸವನ್ನು ಸಂಘಟಿಸಲು ಸಾಧ್ಯವಾಗಿಸುತ್ತದೆ.

ಹೀಗಾಗಿ, ಭರವಸೆಗಳನ್ನು ತಿಳಿದುಕೊಳ್ಳುವುದರಿಂದ Async/Await ತತ್ವಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ಸುಲಭವಾಗುತ್ತದೆ.

ವಾಕ್ಯ

ಸಾಮಾನ್ಯವಾಗಿ ಇದು ಎರಡು ಕೀವರ್ಡ್‌ಗಳನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ: ಅಸಿಂಕ್ ಮತ್ತು ನಿರೀಕ್ಷಿಸಿ. ಮೊದಲ ಪದವು ಕಾರ್ಯವನ್ನು ಅಸಮಕಾಲಿಕವಾಗಿ ಪರಿವರ್ತಿಸುತ್ತದೆ. ಅಂತಹ ಕಾರ್ಯಗಳು ನಿರೀಕ್ಷೆಯ ಬಳಕೆಯನ್ನು ಅನುಮತಿಸುತ್ತದೆ. ಬೇರೆ ಯಾವುದೇ ಸಂದರ್ಭದಲ್ಲಿ, ಈ ಕಾರ್ಯವನ್ನು ಬಳಸುವುದರಿಂದ ದೋಷ ಉಂಟಾಗುತ್ತದೆ.

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

ಅಸಿಂಕ್ ಅನ್ನು ಫಂಕ್ಷನ್ ಘೋಷಣೆಯ ಪ್ರಾರಂಭದಲ್ಲಿ ಮತ್ತು ಬಾಣದ ಕಾರ್ಯದ ಸಂದರ್ಭದಲ್ಲಿ, "=" ಚಿಹ್ನೆ ಮತ್ತು ಆವರಣಗಳ ನಡುವೆ ಸೇರಿಸಲಾಗುತ್ತದೆ.

ಈ ಕಾರ್ಯಗಳನ್ನು ವಸ್ತುವಿನಲ್ಲಿ ವಿಧಾನಗಳಾಗಿ ಇರಿಸಬಹುದು ಅಥವಾ ವರ್ಗ ಘೋಷಣೆಯಲ್ಲಿ ಬಳಸಬಹುದು.

// 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! ವರ್ಗ ಕನ್‌ಸ್ಟ್ರಕ್ಟರ್‌ಗಳು ಮತ್ತು ಗೆಟರ್‌ಗಳು/ಸೆಟ್ಟರ್‌ಗಳು ಅಸಮಕಾಲಿಕವಾಗಿರಲು ಸಾಧ್ಯವಿಲ್ಲ ಎಂಬುದನ್ನು ನೆನಪಿನಲ್ಲಿಟ್ಟುಕೊಳ್ಳುವುದು ಯೋಗ್ಯವಾಗಿದೆ.

ಸೆಮ್ಯಾಂಟಿಕ್ಸ್ ಮತ್ತು ಎಕ್ಸಿಕ್ಯೂಶನ್ ನಿಯಮಗಳು

Async ಕಾರ್ಯಗಳು ಮೂಲತಃ ಪ್ರಮಾಣಿತ JS ಕಾರ್ಯಗಳಿಗೆ ಹೋಲುತ್ತವೆ, ಆದರೆ ವಿನಾಯಿತಿಗಳಿವೆ.

ಹೀಗಾಗಿ, ಅಸಿಂಕ್ ಕಾರ್ಯಗಳು ಯಾವಾಗಲೂ ಭರವಸೆಗಳನ್ನು ನೀಡುತ್ತವೆ:

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

ನಿರ್ದಿಷ್ಟವಾಗಿ, fn ಹಲೋ ಸ್ಟ್ರಿಂಗ್ ಅನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. ಸರಿ, ಇದು ಅಸಮಕಾಲಿಕ ಕಾರ್ಯವಾಗಿರುವುದರಿಂದ, ಸ್ಟ್ರಿಂಗ್ ಮೌಲ್ಯವು ಕನ್ಸ್ಟ್ರಕ್ಟರ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಭರವಸೆಯಲ್ಲಿ ಸುತ್ತುತ್ತದೆ.

ಅಸಿಂಕ್ ಇಲ್ಲದ ಪರ್ಯಾಯ ವಿನ್ಯಾಸ ಇಲ್ಲಿದೆ:

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

ಈ ಸಂದರ್ಭದಲ್ಲಿ, ಭರವಸೆಯನ್ನು "ಕೈಯಾರೆ" ಹಿಂತಿರುಗಿಸಲಾಗುತ್ತದೆ. ಅಸಮಕಾಲಿಕ ಕಾರ್ಯವು ಯಾವಾಗಲೂ ಹೊಸ ಭರವಸೆಯಲ್ಲಿ ಸುತ್ತುತ್ತದೆ.

ಹಿಂತಿರುಗಿಸುವ ಮೌಲ್ಯವು ಪ್ರಾಚೀನವಾಗಿದ್ದರೆ, ಅಸಿಂಕ್ ಕಾರ್ಯವು ಅದನ್ನು ಭರವಸೆಯಲ್ಲಿ ಸುತ್ತುವ ಮೂಲಕ ಮೌಲ್ಯವನ್ನು ಹಿಂದಿರುಗಿಸುತ್ತದೆ. ಹಿಂತಿರುಗಿಸುವ ಮೌಲ್ಯವು ಭರವಸೆಯ ವಸ್ತುವಾಗಿದ್ದರೆ, ಅದರ ನಿರ್ಣಯವನ್ನು ಹೊಸ ಭರವಸೆಯಲ್ಲಿ ಹಿಂತಿರುಗಿಸಲಾಗುತ್ತದೆ.

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

ಆದರೆ ಅಸಮಕಾಲಿಕ ಕ್ರಿಯೆಯೊಳಗೆ ದೋಷವಿದ್ದರೆ ಏನಾಗುತ್ತದೆ?

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

ಅದನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸದಿದ್ದರೆ, foo() ನಿರಾಕರಣೆಯೊಂದಿಗೆ ಭರವಸೆಯನ್ನು ಹಿಂದಿರುಗಿಸುತ್ತದೆ. ಈ ಪರಿಸ್ಥಿತಿಯಲ್ಲಿ, Promise.resolve ಬದಲಿಗೆ ದೋಷವನ್ನು ಹೊಂದಿರುವ Promise.reject ಅನ್ನು ಹಿಂತಿರುಗಿಸಲಾಗುತ್ತದೆ.

ಅಸಿಂಕ್ ಫಂಕ್ಷನ್‌ಗಳು ಯಾವಾಗಲೂ ವಾಗ್ದಾನವನ್ನು ನೀಡುತ್ತದೆ, ಏನನ್ನು ಹಿಂತಿರುಗಿಸಲಾಗುತ್ತದೆ ಎಂಬುದರ ಹೊರತಾಗಿಯೂ.

ಪ್ರತಿ ಕಾಯುವಿಕೆಯಲ್ಲೂ ಅಸಮಕಾಲಿಕ ಕಾರ್ಯಗಳು ವಿರಾಮಗೊಳ್ಳುತ್ತವೆ.

ನಿರೀಕ್ಷಿಸಿ ಅಭಿವ್ಯಕ್ತಿಗಳ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುತ್ತದೆ. ಆದ್ದರಿಂದ, ಅಭಿವ್ಯಕ್ತಿ ಭರವಸೆಯಾಗಿದ್ದರೆ, ಭರವಸೆಯನ್ನು ಪೂರೈಸುವವರೆಗೆ ಅಸಿಂಕ್ ಕಾರ್ಯವನ್ನು ಸ್ಥಗಿತಗೊಳಿಸಲಾಗುತ್ತದೆ. ಅಭಿವ್ಯಕ್ತಿ ಭರವಸೆಯಾಗಿಲ್ಲದಿದ್ದರೆ, ಅದನ್ನು Promise.resolve ಮೂಲಕ ಭರವಸೆಯಾಗಿ ಪರಿವರ್ತಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ನಂತರ ಪೂರ್ಣಗೊಳಿಸಲಾಗುತ್ತದೆ.

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

ಮತ್ತು ಎಫ್ಎನ್ ಕಾರ್ಯವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದರ ವಿವರಣೆ ಇಲ್ಲಿದೆ.

  • ಅದನ್ನು ಕರೆದ ನಂತರ, ಮೊದಲ ಸಾಲನ್ನು const a = ನಿರೀಕ್ಷಿಸಿ 9 ರಿಂದ ಪರಿವರ್ತಿಸಲಾಗುತ್ತದೆ; const a = ನಿರೀಕ್ಷಿಸಿ Promise.resolve(9);.
  • Await ಅನ್ನು ಬಳಸಿದ ನಂತರ, a ಅದರ ಮೌಲ್ಯವನ್ನು ಪಡೆಯುವವರೆಗೆ ಕಾರ್ಯದ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯನ್ನು ಅಮಾನತುಗೊಳಿಸಲಾಗುತ್ತದೆ (ಪ್ರಸ್ತುತ ಪರಿಸ್ಥಿತಿಯಲ್ಲಿ ಇದು 9 ಆಗಿದೆ).
  • delayAndGetRandom(1000) fn ಕಾರ್ಯವನ್ನು ಪೂರ್ಣಗೊಳಿಸುವವರೆಗೆ (1 ಸೆಕೆಂಡಿನ ನಂತರ) ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಯನ್ನು ವಿರಾಮಗೊಳಿಸುತ್ತದೆ. ಇದು 1 ಸೆಕೆಂಡಿಗೆ ಎಫ್ಎನ್ ಕಾರ್ಯವನ್ನು ಪರಿಣಾಮಕಾರಿಯಾಗಿ ನಿಲ್ಲಿಸುತ್ತದೆ.
  • delayAndGetRandom(1000) ಪರಿಹಾರದ ಮೂಲಕ ಯಾದೃಚ್ಛಿಕ ಮೌಲ್ಯವನ್ನು ಹಿಂದಿರುಗಿಸುತ್ತದೆ, ನಂತರ ಅದನ್ನು ವೇರಿಯೇಬಲ್ b ಗೆ ನಿಯೋಜಿಸಲಾಗುತ್ತದೆ.
  • ಸರಿ, ವೇರಿಯೇಬಲ್ c ಯೊಂದಿಗಿನ ಪ್ರಕರಣವು ವೇರಿಯಬಲ್ a ಯಂತೆಯೇ ಇರುತ್ತದೆ. ಅದರ ನಂತರ, ಎಲ್ಲವೂ ಒಂದು ಸೆಕೆಂಡಿಗೆ ನಿಲ್ಲುತ್ತದೆ, ಆದರೆ ಈಗ delayAndGetRandom(1000) ಏನನ್ನೂ ಹಿಂತಿರುಗಿಸುವುದಿಲ್ಲ ಏಕೆಂದರೆ ಅದು ಅಗತ್ಯವಿಲ್ಲ.
  • ಪರಿಣಾಮವಾಗಿ, ಎ + ಬಿ * ಸಿ ಸೂತ್ರವನ್ನು ಬಳಸಿಕೊಂಡು ಮೌಲ್ಯಗಳನ್ನು ಲೆಕ್ಕಹಾಕಲಾಗುತ್ತದೆ. ಫಲಿತಾಂಶವನ್ನು Promise.resolve ಬಳಸಿಕೊಂಡು ವಾಗ್ದಾನದಲ್ಲಿ ಸುತ್ತಿ ಕಾರ್ಯದ ಮೂಲಕ ಹಿಂತಿರುಗಿಸಲಾಗುತ್ತದೆ.

ಈ ವಿರಾಮಗಳು ES6 ನಲ್ಲಿನ ಜನರೇಟರ್‌ಗಳನ್ನು ನೆನಪಿಸುತ್ತವೆ, ಆದರೆ ಅದರಲ್ಲಿ ಏನಾದರೂ ಇದೆ ನಿಮ್ಮ ಕಾರಣಗಳು.

ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸುವುದು

ಸರಿ, ಈಗ ಮೇಲೆ ತಿಳಿಸಿದ ಸಮಸ್ಯೆಗೆ ಪರಿಹಾರವನ್ನು ನೋಡೋಣ.

FinishMyTask ಕಾರ್ಯವು queryDatabase, sendEmail, logTaskInFile, ಮತ್ತು ಇತರ ಕಾರ್ಯಾಚರಣೆಗಳ ಫಲಿತಾಂಶಗಳಿಗಾಗಿ ಕಾಯಲು Await ಅನ್ನು ಬಳಸುತ್ತದೆ. ನೀವು ಈ ಪರಿಹಾರವನ್ನು ಭರವಸೆಗಳನ್ನು ಬಳಸಿದ ಒಂದಕ್ಕೆ ಹೋಲಿಸಿದರೆ, ಹೋಲಿಕೆಗಳು ಸ್ಪಷ್ಟವಾಗುತ್ತವೆ. ಆದಾಗ್ಯೂ, Async/Await ಆವೃತ್ತಿಯು ಎಲ್ಲಾ ವಾಕ್ಯರಚನೆಯ ಸಂಕೀರ್ಣತೆಗಳನ್ನು ಹೆಚ್ಚು ಸರಳಗೊಳಿಸುತ್ತದೆ. ಈ ಸಂದರ್ಭದಲ್ಲಿ, .then/.catch ನಂತಹ ಹೆಚ್ಚಿನ ಸಂಖ್ಯೆಯ ಕಾಲ್‌ಬ್ಯಾಕ್‌ಗಳು ಮತ್ತು ಚೈನ್‌ಗಳು ಇರುವುದಿಲ್ಲ.

ಸಂಖ್ಯೆಗಳ ಔಟ್ಪುಟ್ನೊಂದಿಗೆ ಇಲ್ಲಿ ಪರಿಹಾರವಿದೆ, ಎರಡು ಆಯ್ಕೆಗಳಿವೆ.

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

ಮತ್ತು ಇಲ್ಲಿ ಅಸಿಂಕ್ ಕಾರ್ಯಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಪರಿಹಾರವಿದೆ.

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

ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ ದೋಷ

ನಿಭಾಯಿಸದ ದೋಷಗಳು ತಿರಸ್ಕರಿಸಿದ ಭರವಸೆಯಲ್ಲಿ ಸುತ್ತುತ್ತವೆ. ಆದಾಗ್ಯೂ, ಅಸಿಂಕ್ ಕಾರ್ಯಗಳು ಸಿಂಕ್ರೊನಸ್ ಆಗಿ ದೋಷಗಳನ್ನು ನಿರ್ವಹಿಸಲು ಪ್ರಯತ್ನಿಸಿ/ಕ್ಯಾಚ್ ಅನ್ನು ಬಳಸಬಹುದು.

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() ಒಂದು ಅಸಮಕಾಲಿಕ ಕಾರ್ಯವಾಗಿದ್ದು ಅದು ಯಶಸ್ವಿಯಾಗುತ್ತದೆ ("ಪರಿಪೂರ್ಣ ಸಂಖ್ಯೆ") ಅಥವಾ ದೋಷದೊಂದಿಗೆ ವಿಫಲಗೊಳ್ಳುತ್ತದೆ ("ಕ್ಷಮಿಸಿ, ಸಂಖ್ಯೆ ತುಂಬಾ ದೊಡ್ಡದು").

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

ಮೇಲಿನ ಉದಾಹರಣೆಯು canRejectOrReturn ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲು ನಿರೀಕ್ಷಿಸುತ್ತದೆಯಾದ್ದರಿಂದ, ಅದರ ಸ್ವಂತ ವೈಫಲ್ಯವು ಕ್ಯಾಚ್ ಬ್ಲಾಕ್ನ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆಗೆ ಕಾರಣವಾಗುತ್ತದೆ. ಪರಿಣಾಮವಾಗಿ, ಫಂಕ್ಷನ್ ಫೂ ಅನಿರ್ದಿಷ್ಟವಾಗಿ (ಪ್ರಯತ್ನ ಬ್ಲಾಕ್‌ನಲ್ಲಿ ಏನನ್ನೂ ಹಿಂತಿರುಗಿಸದಿದ್ದಾಗ) ಅಥವಾ ಹಿಡಿದ ದೋಷದೊಂದಿಗೆ ಕೊನೆಗೊಳ್ಳುತ್ತದೆ. ಪರಿಣಾಮವಾಗಿ, ಈ ಕಾರ್ಯವು ವಿಫಲವಾಗುವುದಿಲ್ಲ ಏಕೆಂದರೆ ಪ್ರಯತ್ನಿಸಿ/ಕ್ಯಾಚ್ ಫಂಕ್ಷನ್ ಫೂ ಅನ್ನು ಸ್ವತಃ ನಿರ್ವಹಿಸುತ್ತದೆ.

ಇನ್ನೊಂದು ಉದಾಹರಣೆ ಇಲ್ಲಿದೆ:

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

ಉದಾಹರಣೆಯಲ್ಲಿ, canRejectOrReturn ಅನ್ನು foo ನಿಂದ ಹಿಂತಿರುಗಿಸಲಾಗುತ್ತದೆ ಎಂಬ ಅಂಶಕ್ಕೆ ಗಮನ ಕೊಡುವುದು ಯೋಗ್ಯವಾಗಿದೆ. ಫೂ ಈ ಸಂದರ್ಭದಲ್ಲಿ ಪರಿಪೂರ್ಣ ಸಂಖ್ಯೆಯೊಂದಿಗೆ ಕೊನೆಗೊಳ್ಳುತ್ತದೆ ಅಥವಾ ದೋಷವನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ ("ಕ್ಷಮಿಸಿ, ಸಂಖ್ಯೆ ತುಂಬಾ ದೊಡ್ಡದು"). ಕ್ಯಾಚ್ ಬ್ಲಾಕ್ ಅನ್ನು ಎಂದಿಗೂ ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುವುದಿಲ್ಲ.

ಸಮಸ್ಯೆ ಏನೆಂದರೆ canRejectOrReturn ನಿಂದ ರವಾನಿಸಲಾದ ಭರವಸೆಯನ್ನು foo ಹಿಂದಿರುಗಿಸುತ್ತದೆ. ಆದ್ದರಿಂದ ಫೂಗೆ ಪರಿಹಾರವು canRejectOrReturn ಗೆ ಪರಿಹಾರವಾಗುತ್ತದೆ. ಈ ಸಂದರ್ಭದಲ್ಲಿ, ಕೋಡ್ ಕೇವಲ ಎರಡು ಸಾಲುಗಳನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ:

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

ನೀವು ನಿರೀಕ್ಷಿಸಿ ಮತ್ತು ಒಟ್ಟಿಗೆ ಹಿಂತಿರುಗಿದರೆ ಏನಾಗುತ್ತದೆ ಎಂಬುದು ಇಲ್ಲಿದೆ:

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

ಮೇಲಿನ ಕೋಡ್‌ನಲ್ಲಿ, ಫೂ ಒಂದು ಪರಿಪೂರ್ಣ ಸಂಖ್ಯೆ ಮತ್ತು ಹಿಡಿದಿರುವ ದೋಷ ಎರಡರಿಂದಲೂ ಯಶಸ್ವಿಯಾಗಿ ನಿರ್ಗಮಿಸುತ್ತದೆ. ಇಲ್ಲಿ ಯಾವುದೇ ನಿರಾಕರಣೆ ಇರುವುದಿಲ್ಲ. ಆದರೆ foo canRejectOrReturn ನೊಂದಿಗೆ ಹಿಂತಿರುಗುತ್ತಾನೆ, ವ್ಯಾಖ್ಯಾನಿಸದೆ ಅಲ್ಲ. ರಿಟರ್ನ್ ವೇಯ್ಟ್ canRejectOrReturn() ಸಾಲನ್ನು ತೆಗೆದುಹಾಕುವ ಮೂಲಕ ಇದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳೋಣ:

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

ಸಾಮಾನ್ಯ ತಪ್ಪುಗಳು ಮತ್ತು ಮೋಸಗಳು

ಕೆಲವು ಸಂದರ್ಭಗಳಲ್ಲಿ, Async/Await ಅನ್ನು ಬಳಸುವುದು ದೋಷಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು.

ಮರೆತು ಕಾಯುತ್ತಿದೆ

ಇದು ಆಗಾಗ್ಗೆ ಸಂಭವಿಸುತ್ತದೆ - ಭರವಸೆಯ ಮೊದಲು ಕಾಯುವ ಕೀವರ್ಡ್ ಮರೆತುಹೋಗಿದೆ:

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

ನೀವು ನೋಡುವಂತೆ, ಕೋಡ್‌ನಲ್ಲಿ ಯಾವುದೇ ನಿರೀಕ್ಷೆ ಅಥವಾ ಹಿಂತಿರುಗುವಿಕೆ ಇಲ್ಲ. ಆದ್ದರಿಂದ ಫೂ ಯಾವಾಗಲೂ 1 ಸೆಕೆಂಡ್ ವಿಳಂಬವಿಲ್ಲದೆ ವ್ಯಾಖ್ಯಾನಿಸದೆ ನಿರ್ಗಮಿಸುತ್ತದೆ. ಆದರೆ ಭರವಸೆ ಈಡೇರಿಸಲಾಗುವುದು. ಅದು ದೋಷ ಅಥವಾ ನಿರಾಕರಣೆಯನ್ನು ಎಸೆದರೆ, ನಂತರ UnhandledPromiseRejectionWarning ಎಂದು ಕರೆಯಲಾಗುವುದು.

ಕಾಲ್‌ಬ್ಯಾಕ್‌ಗಳಲ್ಲಿ ಅಸಿಂಕ್ ಕಾರ್ಯಗಳು

Async ಕಾರ್ಯಗಳನ್ನು .map ಅಥವಾ .filter ನಲ್ಲಿ ಕಾಲ್‌ಬ್ಯಾಕ್‌ಗಳಾಗಿ ಹೆಚ್ಚಾಗಿ ಬಳಸಲಾಗುತ್ತದೆ. FetchPublicReposCount(ಬಳಕೆದಾರಹೆಸರು) ಕಾರ್ಯವು ಒಂದು ಉದಾಹರಣೆಯಾಗಿದೆ, ಇದು GitHub ನಲ್ಲಿ ತೆರೆದ ರೆಪೊಸಿಟರಿಗಳ ಸಂಖ್ಯೆಯನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. ನಮಗೆ ಅಗತ್ಯವಿರುವ ಮೂರು ಬಳಕೆದಾರರಿದ್ದಾರೆ ಎಂದು ಹೇಳೋಣ. ಈ ಕಾರ್ಯಕ್ಕಾಗಿ ಕೋಡ್ ಇಲ್ಲಿದೆ:

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

ನಮಗೆ ArfatSalman, octocat, norvig ಖಾತೆಗಳ ಅಗತ್ಯವಿದೆ. ಈ ಸಂದರ್ಭದಲ್ಲಿ ನಾವು ಮಾಡುತ್ತೇವೆ:

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

.map ಕಾಲ್‌ಬ್ಯಾಕ್‌ನಲ್ಲಿ ಅವೇಟ್‌ಗೆ ಗಮನ ಕೊಡುವುದು ಯೋಗ್ಯವಾಗಿದೆ. ಇಲ್ಲಿ ಎಣಿಕೆಗಳು ಭರವಸೆಗಳ ಒಂದು ಶ್ರೇಣಿಯಾಗಿದೆ ಮತ್ತು .map ಪ್ರತಿ ನಿರ್ದಿಷ್ಟಪಡಿಸಿದ ಬಳಕೆದಾರರಿಗೆ ಅನಾಮಧೇಯ ಕಾಲ್‌ಬ್ಯಾಕ್ ಆಗಿದೆ.

ನಿರೀಕ್ಷೆಯ ಅತಿಯಾದ ಸ್ಥಿರ ಬಳಕೆ

ಈ ಕೋಡ್ ಅನ್ನು ಉದಾಹರಣೆಯಾಗಿ ತೆಗೆದುಕೊಳ್ಳೋಣ:

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

ಇಲ್ಲಿ ರೆಪೋ ಸಂಖ್ಯೆಯನ್ನು ಎಣಿಕೆ ವೇರಿಯೇಬಲ್‌ನಲ್ಲಿ ಇರಿಸಲಾಗುತ್ತದೆ, ನಂತರ ಈ ಸಂಖ್ಯೆಯನ್ನು ಎಣಿಕೆಗಳ ಶ್ರೇಣಿಗೆ ಸೇರಿಸಲಾಗುತ್ತದೆ. ಕೋಡ್‌ನ ಸಮಸ್ಯೆ ಎಂದರೆ ಸರ್ವರ್‌ನಿಂದ ಮೊದಲ ಬಳಕೆದಾರರ ಡೇಟಾ ಬರುವವರೆಗೆ, ಎಲ್ಲಾ ನಂತರದ ಬಳಕೆದಾರರು ಸ್ಟ್ಯಾಂಡ್‌ಬೈ ಮೋಡ್‌ನಲ್ಲಿರುತ್ತಾರೆ. ಹೀಗಾಗಿ, ಒಂದು ಸಮಯದಲ್ಲಿ ಒಬ್ಬ ಬಳಕೆದಾರರನ್ನು ಮಾತ್ರ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲಾಗುತ್ತದೆ.

ಉದಾಹರಣೆಗೆ, ಒಬ್ಬ ಬಳಕೆದಾರರನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸುಮಾರು 300 ಎಂಎಸ್ ತೆಗೆದುಕೊಂಡರೆ, ಎಲ್ಲಾ ಬಳಕೆದಾರರಿಗೆ ಇದು ಈಗಾಗಲೇ ಎರಡನೆಯದು; ರೇಖೀಯವಾಗಿ ಕಳೆದ ಸಮಯವು ಬಳಕೆದಾರರ ಸಂಖ್ಯೆಯನ್ನು ಅವಲಂಬಿಸಿರುತ್ತದೆ. ಆದರೆ ರೆಪೊ ಸಂಖ್ಯೆಯನ್ನು ಪಡೆಯುವುದು ಪರಸ್ಪರ ಅವಲಂಬಿಸಿರುವುದಿಲ್ಲವಾದ್ದರಿಂದ, ಪ್ರಕ್ರಿಯೆಗಳನ್ನು ಸಮಾನಾಂತರಗೊಳಿಸಬಹುದು. ಇದಕ್ಕೆ .map ಮತ್ತು 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 ಭರವಸೆಗಳ ಒಂದು ಶ್ರೇಣಿಯನ್ನು ಇನ್‌ಪುಟ್ ಆಗಿ ಸ್ವೀಕರಿಸುತ್ತದೆ ಮತ್ತು ಭರವಸೆಯನ್ನು ಹಿಂದಿರುಗಿಸುತ್ತದೆ. ಎರಡನೆಯದು, ರಚನೆಯಲ್ಲಿನ ಎಲ್ಲಾ ಭರವಸೆಗಳು ಪೂರ್ಣಗೊಂಡ ನಂತರ ಅಥವಾ ಮೊದಲ ನಿರಾಕರಣೆಯಲ್ಲಿ ಪೂರ್ಣಗೊಂಡಿದೆ. ಅವೆಲ್ಲವೂ ಒಂದೇ ಸಮಯದಲ್ಲಿ ಪ್ರಾರಂಭವಾಗದಿರಬಹುದು - ಏಕಕಾಲಿಕ ಪ್ರಾರಂಭವನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು, ನೀವು p-map ಅನ್ನು ಬಳಸಬಹುದು.

ತೀರ್ಮಾನಕ್ಕೆ

ಅಸಿಂಕ್ ಕಾರ್ಯಗಳು ಅಭಿವೃದ್ಧಿಗೆ ಹೆಚ್ಚು ಮುಖ್ಯವಾಗುತ್ತಿವೆ. ಸರಿ, ಅಸಿಂಕ್ ಕಾರ್ಯಗಳ ಹೊಂದಾಣಿಕೆಯ ಬಳಕೆಗಾಗಿ, ನೀವು ಬಳಸಬೇಕು ಅಸಿಂಕ್ ಪುನರಾವರ್ತಕಗಳು. ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಡೆವಲಪರ್ ಇದರಲ್ಲಿ ಚೆನ್ನಾಗಿ ತಿಳಿದಿರಬೇಕು.

ಸ್ಕಿಲ್‌ಬಾಕ್ಸ್ ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ:

ಮೂಲ: www.habr.com

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ