From d10928c323f7646a5f7743b4bc319b9347f0d78d Mon Sep 17 00:00:00 2001 From: Saiful Date: Thu, 21 Jan 2021 09:24:45 +0600 Subject: [PATCH 1/3] fix merge conflict --- .../2-async-iterators-generators/article.md | 246 +----------------- 1 file changed, 4 insertions(+), 242 deletions(-) diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md index 6bce3e083..4b2056752 100644 --- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md +++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md @@ -1,79 +1,36 @@ -<<<<<<< HEAD # অ্যাসিঙ্ক ইটারেটর এবং জেনারেটর অ্যাসিঙ্ক্রোনাসলি আসা ডাটাগুলোকে অ্যাসিঙ্ক্রোনাস ইটারেটরের সাহায্যে আমরা আমাদের চাহিদা মত ইটারেট করতে পারি। উদাহরণস্বরূপ, যখন আমরা নেটওয়ার্কের মাধ্যমে ছোট ছোট অংশ ডাউনলোড করি। এটি অ্যাসিঙ্ক্রোনাস জেনারেটরের সাহায্যে আরো সহজে করা যায়। -======= -# Async iteration and generators - -Asynchronous iteration allow us to iterate over data that comes asynchronously, on-demand. Like, for instance, when we download something chunk-by-chunk over a network. And asynchronous generators make it even more convenient. ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d চলুন প্রথমে একটি উদাহরণ দেখি, সিনট্যাক্সগুলো বুঝার চেষ্টা করি এবং পরে একটি বাস্তবিক ব্যবহার দেখব। -<<<<<<< HEAD ## অ্যাসিঙ্ক ইটারেটর অ্যাসিঙ্ক্রোনাস ইটারেটর অনেকটা সাধারণ ইটারেটরের মত, শুধু কিছু সিনট্যাক্সের পার্থক্য আছে। একটি "সাধারণ" ইটারেবল অবজেক্ট, যা আমরা এই অধ্যায়ে জানতে পারি , দেখতে অনেকটা এমনঃ -======= -## Recall iterables - -Let's recall the topic about iterables. - -The idea is that we have an object, such as `range` here: -```js -let range = { - from: 1, - to: 5 -}; -``` - -...And we'd like to use `for..of` loop on it, such as `for(value of range)`, to get values from `1` to `5`. - -In other words, we want to add an *iteration ability* to the object. - -That can be implemented using a special method with the name `Symbol.iterator`: - -- This method is called in by the `for..of` construct when the loop is started, and it should return an object with the `next` method. -- For each iteration, the `next()` method is invoked for the next value. -- The `next()` should return a value in the form `{done: true/false, value:}`, where `done:true` means the end of the loop. - -Here's an implementation for the iterable `range`: ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d ```js run let range = { from: 1, to: 5, -<<<<<<< HEAD // for..of range কে কল করা হলে সবার শুরুতে এই মেথডটি এক্সিকিউট হবে -======= ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d *!* [Symbol.iterator]() { // called once, in the beginning of for..of */!* -<<<<<<< HEAD // ...এটি রিটার্ন করে ইটারেটর অবজেক্ট: // পরবর্তীতে, for..of শুধু অবজেক্টির সাথে কাজ করে এবং এর মাধ্যমে আমরা মান গুলো জানতে পারি // পরবর্তী মানটি next() এর মাধ্যমে জানা যায় -======= ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d return { current: this.from, last: this.to, -<<<<<<< HEAD - // for..of লুপের প্রতিবার ইটারেশনে next() কল হয় + // for..of লুপের প্রতিবার ইটারেশনে next() কল হয় *!* next() { // (2) // এটি রিটার্ন করবে একটি অবজেক্ট {done:.., value :...} -======= -*!* - next() { // called every iteration, to get the next value ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d */!* if (this.current <= this.last) { return { done: false, value: this.current++ }; @@ -91,41 +48,18 @@ for(let value of range) { ``` যদি আপনি সাধারণ ইটারেটর নিয়ে আরো বিস্তারিত জানতে চান দয়া করে এটি দেখুন [ইটারেবল চ্যাপ্টার](info:iterable)। -<<<<<<< HEAD অ্যাসিঙ্ক্রোনাসলি ইটারেটরেবল অবজেক্ট তৈরি করতে: 1. আমাদের `Symbol.iterator` এর পরিবর্তে `Symbol.asyncIterator` ব্যবহার করা লাগবে। 2. `next()` অবশ্যই একটি প্রমিস রিটার্ন করবে। 3. এইধরনের অবজেক্ট ইটারেট করতে, আমরা ব্যবহার করব `for await (let item of iterable)` লুপ। চলুন আগেরটির মত একটি ইটারেটরেবল `range` অবজেক্ট তৈরি করি কিন্তু এটি অ্যাসিঙ্ক্রোনাসলি প্রতি সেকেন্ডে একটি মান রিটার্ন করবেঃ -======= -If anything is unclear, please visit the chapter [](info:iterable), it gives all the details about regular iterables. - -## Async iterables - -Asynchronous iteration is needed when values come asynchronously: after `setTimeout` or another kind of delay. - -The most common case is that the object needs to make a network request to deliver the next value, we'll see a real-life example of it a bit later. - -To make an object iterable asynchronously: - -1. Use `Symbol.asyncIterator` instead of `Symbol.iterator`. -2. The `next()` method should return a promise (to be fulfilled with the next value). - - The `async` keyword handles it, we can simply make `async next()`. -3. To iterate over such an object, we should use a `for await (let item of iterable)` loop. - - Note the `await` word. - -As a starting example, let's make an iterable `range` object, similar like the one before, but now it will return values asynchronously, one per second. - -All we need to do is to perform a few replacements in the code above: ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d ```js run let range = { from: 1, to: 5, -<<<<<<< HEAD // for await..of কে কল করা হলে সবার শুরুতে এই মেথডটি এক্সিকিউট হবে *!* [Symbol.asyncIterator]() { // (1) @@ -133,17 +67,11 @@ let range = { // ...এটি রিটার্ন করে ইটারেটর অবজেক্ট: // পরবর্তীতে, for await..of শুধু অবজেক্টির সাথে কাজ করে এবং এর মাধ্যমে আমরা মান গুলো জানতে পারি // পরবর্তী মানটি next() এর মাধ্যমে জানা যায় -======= -*!* - [Symbol.asyncIterator]() { // (1) -*/!* ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d return { current: this.from, last: this.to, -<<<<<<< HEAD - //for await..of লুপের প্রতিবার ইটারেশনে next() কল হয় + //for await..of লুপের প্রতিবার ইটারেশনে next() কল হয় *!* async next() { // (2) // এটি রিটার্ন করবে একটি অবজেক্ট {done:.., value :...} @@ -152,14 +80,6 @@ let range = { *!* // অ্যাসিঙ্ক কাজগুলো আমরা এওয়েট এর ভিতর করতে পারিঃ -======= -*!* - async next() { // (2) -*/!* - -*!* - // note: we can use "await" inside the async next: ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d await new Promise(resolve => setTimeout(resolve, 1000)); // (3) */!* @@ -191,11 +111,7 @@ let range = { 3. The `next()` method doesn't have to be `async`, it may be a regular method returning a promise, but `async` allows to use `await`, so that's convenient. Here we just delay for a second `(3)`। 4. ইটারেটের জন্য আমরা `for await(let value of range)` `(4)` ব্যবহার করি, লুপে "for" এর পর "await" ব্যবহার করুন। এটি প্রথমে কল করে `range[Symbol.asyncIterator]()` কে এবং পরে মানের জন্য `next()` কে। -<<<<<<< HEAD ছোট একটি চিটশিট: -======= -Here's a small table with the differences: ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d | | ইটারেটর | অ্যাসিঙ্ক ইটারেটর | |-------|-----------|-----------------| @@ -213,7 +129,6 @@ Here's a small table with the differences: alert( [...range] ); // Error, no Symbol.iterator ``` -<<<<<<< HEAD এটিই স্বাভাবিক কেননা এটি `Symbol.iterator` কে খুঁজে `for..of` এর মত `Symbol.asyncIterator` কে না। ```` @@ -222,22 +137,6 @@ alert( [...range] ); // Error, no Symbol.iterator ইতোমধ্যে আমরা জানি জাভাস্ক্রিপ্ট জেনারেটর সাপোর্ট করে যা ইটারেবল। চলুন একটি সিক্যুয়েন্স জেনারেটরকে কল করি যা এই অধ্যায়ে [](info:generators) জেনেছিলাম। এটি একটি সিক্যুয়েন্স মান তৈরি করে `start` হতে `end` পর্যন্তঃ -======= -That's natural, as it expects to find `Symbol.iterator`, not `Symbol.asyncIterator`. - -It's also the case for `for..of`: the syntax without `await` needs `Symbol.iterator`. -```` - -## Recall generators - -Now let's recall generators, as they allow to make iteration code much shorter. Most of the time, when we'd like to make an iterable, we'll use generators. - -For sheer simplicity, omitting some important stuff, they are "functions that generate (yield) values". They are explained in detail in the chapter [](info:generators). - -Generators are labelled with `function*` (note the star) and use `yield` to generate a value, then we can use `for..of` to loop over them. - -This example generates a sequence of values from `start` to `end`: ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d ```js run function* generateSequence(start, end) { @@ -251,62 +150,11 @@ for(let value of generateSequence(1, 5)) { } ``` -<<<<<<< HEAD সাধারণ জেনারেটরে আমরা `await` ব্যবহার করতে পারি না। সকল মান সিঙ্ক্রোনাসলি আসেঃ এখানে `for..of` এ কোন লাইনে এ ডিলে হয় না, এটি একটি সিঙ্ক্রোনাস কন্সট্রাক্ট। কিন্ত যদি আমরা জেনারেটর বডিতে `await` ব্যবহার করি কি হবে? যেমন নেটওয়ার্ক রিকুয়েস্টের সাথে কাজ করার জন্য। কোন সমস্যা নেই, আমরা এভাবে `async` কে প্রিপেন্ড করে নিতে পারিঃ -======= -As we already know, to make an object iterable, we should add `Symbol.iterator` to it. - -```js -let range = { - from: 1, - to: 5, -*!* - [Symbol.iterator]() { - return - } -*/!* -} -``` - -A common practice for `Symbol.iterator` is to return a generator, it makes the code shorter, as you can see: - -```js run -let range = { - from: 1, - to: 5, - - *[Symbol.iterator]() { // a shorthand for [Symbol.iterator]: function*() - for(let value = this.from; value <= this.to; value++) { - yield value; - } - } -}; - -for(let value of range) { - alert(value); // 1, then 2, then 3, then 4, then 5 -} -``` - -Please see the chapter [](info:generators) if you'd like more details. - -In regular generators we can't use `await`. All values must come synchronously, as required by the `for..of` construct. - -What if we'd like to generate values asynchronously? From network requests, for instance. - -Let's switch to asynchronous generators to make it possible. - -## Async generators (finally) - -For most practical applications, when we'd like to make an object that asynchronously generates a sequence of values, we can use an asynchronous generator. - -The syntax is simple: prepend `function*` with `async`. That makes the generator asynchronous. - -And then use `for await (...)` to iterate over it, like this: ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d ```js run *!*async*/!* function* generateSequence(start, end) { @@ -314,11 +162,7 @@ And then use `for await (...)` to iterate over it, like this: for (let i = start; i <= end; i++) { *!* -<<<<<<< HEAD // হুররে, আমরা এওয়েট ব্যবহার করতে পারছি! -======= - // Wow, can use await! ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d await new Promise(resolve => setTimeout(resolve, 1000)); */!* @@ -331,30 +175,17 @@ And then use `for await (...)` to iterate over it, like this: let generator = generateSequence(1, 5); for *!*await*/!* (let value of generator) { -<<<<<<< HEAD alert(value); // 1, তারপর 2, তারপর 3, তারপর 4, তারপর 5 -======= - alert(value); // 1, then 2, then 3, then 4, then 5 (with delay between) ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d } })(); ``` -<<<<<<< HEAD এখন আমাদের অ্যাসিঙ্ক জেনারেটর আছে যা `for await...of` এর দ্বারা ইটারেটবল। এটি খুব সহজ, আমরা একটি `async` যুক্ত করি এবং জেনারেটরের মধ্যে প্রমিস অথবা অন্যান্য অ্যাসিঙ্ক ফাংশনের এর উপর ভিত্তি করে `await` ব্যবহার করতে পারি। টেকনিক্যালি, অ্যাসিঙ্ক জেনারেটরের আরেকটি পার্থক্য হল এখন `generator.next()` এই মেথডটিও অ্যাসিঙ্ক্রোনাস, যা একটি প্রমিস রিটার্ন করে। -======= -As the generator is asynchronous, we can use `await` inside it, rely on promises, perform network requests and so on. - -````smart header="Under-the-hood difference" -Technically, if you're an advanced reader who remembers the details about generators, there's an internal difference. - -For async generators, the `generator.next()` method is asynchronous, it returns promises. ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d সাধারণ জেনারেটরে আমরা মান এভাবে পাই `result = generator.next()`. কিন্তু অ্যাসিঙ্ক জেনারেটরে মান পেতে আমাদের `await` যুক্ত করতে হবে, এভাবেঃ @@ -364,7 +195,6 @@ result = await generator.next(); // result = {value: ..., done: true/false} That's why async generators work with `for await...of`. ```` -<<<<<<< HEAD ## অ্যাসিঙ্ক ইটারেটবল। ইতোমধ্যে আমরা জেনেছি ইটারেবল অবজেক্ট তৈরি করতে আমাদের `Symbol.iterator` যুক্ত করতে হয়। @@ -405,15 +235,6 @@ for(let value of range) { এখানে `range` কাস্টম অবজেক্টটি একটি ইটারেবল, এবং `*[Symbol.iterator]` জেনারেটরটি দ্বারা মানগুলো দেখাতে লজিক প্রয়োগ করি। যদি আমরা জেনারেটরে অ্যাসিঙ্ক অ্যাকশন যুক্ত করতে চাই আমাদের `Symbol.iterator` এর পরিবর্তে async `Symbol.asyncIterator` ব্যবহার করতে হবেঃ -======= -### Async iterable range - -Regular generators can be used as `Symbol.iterator` to make the iteration code shorter. - -Similar to that, async generators can be used as `Symbol.asyncIterator` to implement the asynchronous iteration. - -For instance, we can make the `range` object generate values asynchronously, once per second, by replacing synchronous `Symbol.iterator` with asynchronous `Symbol.asyncIterator`: ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d ```js run let range = { @@ -426,7 +247,7 @@ let range = { */!* for(let value = this.from; value <= this.to; value++) { - // দুটি মানের মধ্যেবর্তী কিছুক্ষণের জন্য অপেক্ষা করবে + // দুটি মানের মধ্যেবর্তী কিছুক্ষণের জন্য অপেক্ষা করবে await new Promise(resolve => setTimeout(resolve, 1000)); yield value; @@ -445,25 +266,12 @@ let range = { এখন মানগুলো ১ সেকেন্ড পর পর আসবে। -<<<<<<< HEAD ## একটি বাস্তবিক উদাহরণ এ পর্যন্ত আমরা কিছু সাধারন উদাহরণ এর সাহায্যে বেসিক ব্যাপারগুলো দেখলাম। চলুন এখন আমরা একটি বাস্তবিক ব্যবহার দেখি। -======= -```smart -Technically, we can add both `Symbol.iterator` and `Symbol.asyncIterator` to the object, so it's both synchronously (`for..of`) and asynchronously (`for await..of`) iterable. - -In practice though, that would be an weird thing to do. -``` - -## Real-life example: paginated data - -So far we've seen basic examples, to gain understanding. Now let's review a real-life use case. ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d অনলাইনে অনেক সার্ভিস আছে যারা পেজিনেটেড ডাটা সরবরাহ করে। উদাহরণস্বরূপ, যখন আমাদের ইউজারদের একটি লিস্ট দরকার হয় এটি "এক পেজের" জন্য একটি রিকুয়েস্টে প্রি-ডিফাইন্ড (যেমনঃ ১০০ জন ইউজারের) ডাটা রিটার্ন করে , এবং পরবর্তী পেজে যাওয়ার জন্য একটি URL প্রদান করে। -<<<<<<< HEAD এটি একটি কমন প্যাটার্ন। এটি শুধু ইউজারের জন্য না যেকোন ধরনের লিস্টের জন্য হতে পারে। উদাহরণস্বরূপ, গিটহাব হতে আমরা পেজিনেটেড উপায়ে কমিট নিয়ে আসতে পারিঃ - এই জন্য আমাদের এই `https://api.github.com/repos//commits` URL এ একটি রিকুয়েস্ট করা লাগবে। @@ -483,29 +291,6 @@ for await (let commit of fetchCommits(repo)) { আমরা কমিট নিয়ে আসার জন্য একটি `fetchCommits(repo)` ফাংশন তৈরি করি, যা প্রয়োজনমত রিকুয়েস্ট তৈরি করে। এবং পেজিনেশনের সকল ব্যাপার এটির মাধ্যমে নিয়ন্ত্রিত হয়। এটি একটি সিম্পল `for await..of`। অ্যাসিঙ্ক জেনারেটরের মাধ্যমে আমরা সহজেই এটি তৈরি করতে পারিঃ -======= -This pattern is very common. It's not about users, but just about anything. - -For instance, GitHub allows us to retrieve commits in the same, paginated fashion: - -- We should make a request to `fetch` in the form `https://api.github.com/repos//commits`. -- It responds with a JSON of 30 commits, and also provides a link to the next page in the `Link` header. -- Then we can use that link for the next request, to get more commits, and so on. - -For our code, we'd like to have a simpler way to get commits. - -Let's make a function `fetchCommits(repo)` that gets commits for us, making requests whenever needed. And let it care about all pagination stuff. For us it'll be a simple async iteration `for await..of`. - -So the usage will be like this: - -```js -for await (let commit of fetchCommits("username/repository")) { - // process commit -} -``` - -Here's such function, implemented as async generator: ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d ```js async function* fetchCommits(repo) { @@ -513,11 +298,7 @@ async function* fetchCommits(repo) { while (url) { const response = await fetch(url, { // (1) -<<<<<<< HEAD headers: {'User-Agent': 'Our script'}, // গিটহাবে User-Agent হেডার দরকার -======= - headers: {'User-Agent': 'Our script'}, // github needs any user-agent header ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d }); const body = await response.json(); // (2) রেস্পন্স করবে জেসন (কমিটের অ্যারেসমূহ) @@ -535,24 +316,11 @@ async function* fetchCommits(repo) { } ``` -<<<<<<< HEAD -======= -More explanations about how it works: - -1. We use the browser [fetch](info:fetch) method to download the commits. - - - The initial URL is `https://api.github.com/repos//commits`, and the next page will be in the `Link` header of the response. - - The `fetch` method allows us to supply authorization and other headers if needed -- here GitHub requires `User-Agent`. -2. The commits are returned in JSON format. -3. We should get the next page URL from the `Link` header of the response. It has a special format, so we use a regular expression for that. - - The next page URL may look like `https://api.github.com/repositories/93253246/commits?page=2`. It's generated by GitHub itself. -4. Then we yield the received commits one by one, and when they finish, the next `while(url)` iteration will trigger, making one more request. ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d 1. আমরা রিমোট URL থেকে কিছু ডাউনলোডের জন্য ব্রাউজারের [fetch](info:fetch) মেথডটি ব্যবহার করতে পারি। এটির মাধ্যমে আমরা অথোরাইজেশন এবং অন্যান্য হেডার পাস করতে পারি -- গিটহাব API এ রিকুয়েস্টের জন্য আমাদের `User-Agent` হেডারটি পাঠানো প্রয়োজন 2. `fetch` এর মাধ্যমে আমরা একটি জেসন অবজেক্ট পাই, যা `fetch`এর একটি নির্দিষ্ট মেথড। 3. আমরা পরবর্তী পেজের URL টি রেস্পন্সের `Link` হেডার হতে পাই। এটি একটি স্পেশাল ফরম্যাটে থাকে তাই আমরা রেগুলার এক্সপ্রেশন ব্যবহারের এর মাধ্যমে পরবর্তী পেজের লিঙ্কটি পায়। পরবর্তী পেজের URL টি দেখতে এমন হয় `https://api.github.com/repositories/93253246/commits?page=2`। এটি গিটহাবের মাধ্যমে জেনারেট হয়। -4. তারপর আমরা `yield` এর মাধ্যমে কমিট গুলো রিসিভ করি এবং যখন এটি শেষ হয়, `while(url)` লুপ আবার রান হয় এবং এর ফলে আরো রিকুয়েস্ট জেনারেট হয়। +4. তারপর আমরা `yield` এর মাধ্যমে কমিট গুলো রিসিভ করি এবং যখন এটি শেষ হয়, `while(url)` লুপ আবার রান হয় এবং এর ফলে আরো রিকুয়েস্ট জেনারেট হয়। উদাহরণস্বরূপ (কনসোলে কমিটের অথরের নাম দেখায়): @@ -573,13 +341,7 @@ More explanations about how it works: })(); ``` -<<<<<<< HEAD এটি আমাদের চাহিদামত কাজ করে। এখানে পেজিনেশেনের পুরো ব্যাপারটা ইন্টারনালি সংগঠিত হয় এবং অ্যাসিঙ্ক জেনারেটর আমাদের কমিটগুলো রিটার্ন করে। -======= -That's just what we wanted. - -The internal mechanics of paginated requests is invisible from the outside. For us it's just an async generator that returns commits. ->>>>>>> d6e88647b42992f204f57401160ebae92b358c0d ## সারাংশ From 2018dafaf9666c9a5ecbf7bed29da98aa1d13450 Mon Sep 17 00:00:00 2001 From: Saiful Date: Thu, 21 Jan 2021 10:44:04 +0600 Subject: [PATCH 2/3] fix merge conflict and some new paragraph translate --- .../2-async-iterators-generators/article.md | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md index 4b2056752..231a5af8a 100644 --- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md +++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md @@ -1,10 +1,67 @@ -# অ্যাসিঙ্ক ইটারেটর এবং জেনারেটর +# অ্যাসিঙ্ক ইটারেশন এবং জেনারেটর -অ্যাসিঙ্ক্রোনাসলি আসা ডাটাগুলোকে অ্যাসিঙ্ক্রোনাস ইটারেটরের সাহায্যে আমরা আমাদের চাহিদা মত ইটারেট করতে পারি। উদাহরণস্বরূপ, যখন আমরা নেটওয়ার্কের মাধ্যমে ছোট ছোট অংশ ডাউনলোড করি। এটি অ্যাসিঙ্ক্রোনাস জেনারেটরের সাহায্যে আরো সহজে করা যায়। +অ্যাসিঙ্ক্রোনাসলি আসা ডাটাগুলোকে অ্যাসিঙ্ক্রোনাস ইটারেশনের সাহায্যে আমরা আমাদের চাহিদা মত ইটারেট করতে পারি। উদাহরণস্বরূপ, যখন আমরা নেটওয়ার্কের মাধ্যমে ছোট ছোট অংশ ডাউনলোড করি। এটি অ্যাসিঙ্ক্রোনাস জেনারেটরের সাহায্যে আরো সহজে করা যায়। চলুন প্রথমে একটি উদাহরণ দেখি, সিনট্যাক্সগুলো বুঝার চেষ্টা করি এবং পরে একটি বাস্তবিক ব্যবহার দেখব। +## পুনরায় ইটারেবল + +আসুন পুনরায় ইটারেবলের টপিক্সটি দেখি। + +আমাদের একটি অবজেক্ট আছে, যেমন `range`: +```js +let range = { + from: 1, + to: 5 +}; +``` + +...এবং আমরা `for..of` লুপ চালাব, যেমন `for(value of range)`, `1` হতে `5` পর্যন্ত মানগুলো পেতে। + +অন্য কথায় বলা যায়, আমরা আমাদের অবজেক্টটিতে *iteration ability* সাপোর্ট করাব। + +এটি আমরা করতে পারি একটি বিশেষ মেথডের সাহায্যে `Symbol.iterator`: + +- This method is called in by the `for..of` construct when the loop is started, and it should return an object with the `next` method. +- For each iteration, the `next()` method is invoked for the next value. +- The `next()` should return a value in the form `{done: true/false, value:}`, where `done:true` means the end of the loop. + +Here's an implementation for the iterable `range`: + +```js run +let range = { + from: 1, + to: 5, + +*!* + [Symbol.iterator]() { // called once, in the beginning of for..of +*/!* + return { + current: this.from, + last: this.to, + +*!* + next() { // called every iteration, to get the next value +*/!* + if (this.current <= this.last) { + return { done: false, value: this.current++ }; + } else { + return { done: true }; + } + } + }; + } +}; + +for(let value of range) { + alert(value); // 1 তারপর 2, তারপর 3, তারপর 4, তারপর 5 +} +``` +যদি আপনি সাধারণ ইটারেটর নিয়ে আরো বিস্তারিত জানতে চান দয়া করে এটি দেখুন [ইটারেবল চ্যাপ্টার](info:iterable)। + +If anything is unclear, please visit the chapter [](info:iterable), it gives all the details about regular iterables. + ## অ্যাসিঙ্ক ইটারেটর অ্যাসিঙ্ক্রোনাস ইটারেটর অনেকটা সাধারণ ইটারেটরের মত, শুধু কিছু সিনট্যাক্সের পার্থক্য আছে। From 72f9bf531c0a9f6754142cacc917206bc9baacf5 Mon Sep 17 00:00:00 2001 From: Saiful Date: Mon, 25 Jan 2021 10:35:06 +0600 Subject: [PATCH 3/3] retranslate --- .../2-async-iterators-generators/article.md | 251 ++++++++---------- 1 file changed, 115 insertions(+), 136 deletions(-) diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md index 231a5af8a..fbefb97d8 100644 --- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md +++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md @@ -1,4 +1,3 @@ - # অ্যাসিঙ্ক ইটারেশন এবং জেনারেটর অ্যাসিঙ্ক্রোনাসলি আসা ডাটাগুলোকে অ্যাসিঙ্ক্রোনাস ইটারেশনের সাহায্যে আমরা আমাদের চাহিদা মত ইটারেট করতে পারি। উদাহরণস্বরূপ, যখন আমরা নেটওয়ার্কের মাধ্যমে ছোট ছোট অংশ ডাউনলোড করি। এটি অ্যাসিঙ্ক্রোনাস জেনারেটরের সাহায্যে আরো সহজে করা যায়। @@ -23,11 +22,11 @@ let range = { এটি আমরা করতে পারি একটি বিশেষ মেথডের সাহায্যে `Symbol.iterator`: -- This method is called in by the `for..of` construct when the loop is started, and it should return an object with the `next` method. -- For each iteration, the `next()` method is invoked for the next value. -- The `next()` should return a value in the form `{done: true/false, value:}`, where `done:true` means the end of the loop. +- for..of range কে কল করা হলে সবার শুরুতে এই মেথডটি এক্সিকিউট হবে, এবং এটি একটি অবজেক্ট রিটার্ন করবে যার একটি মেথড `next`। +- for..of লুপের প্রতিবার ইটারেশনে next() কল হয় পরবর্তী মানের জন্য। +- `next()` মেথডটি রিটার্ন করে একটি অবজেক্ট `{done: true/false, value:}`, যেখানে `done:true` দ্বারা বুঝায় লুপের শেষ। -Here's an implementation for the iterable `range`: +এখানে `range` এর জন্য একটি ইটারেবল ইমপ্লিমেন্ট করি: ```js run let range = { @@ -35,14 +34,14 @@ let range = { to: 5, *!* - [Symbol.iterator]() { // called once, in the beginning of for..of + [Symbol.iterator]() { // একবার কল হবে, for..of এর শুরুতে */!* return { current: this.from, last: this.to, *!* - next() { // called every iteration, to get the next value + next() { // প্রতিবার ইটারেশনে পরবর্তী মান টি পাব */!* if (this.current <= this.last) { return { done: false, value: this.current++ }; @@ -58,85 +57,44 @@ for(let value of range) { alert(value); // 1 তারপর 2, তারপর 3, তারপর 4, তারপর 5 } ``` -যদি আপনি সাধারণ ইটারেটর নিয়ে আরো বিস্তারিত জানতে চান দয়া করে এটি দেখুন [ইটারেবল চ্যাপ্টার](info:iterable)। - -If anything is unclear, please visit the chapter [](info:iterable), it gives all the details about regular iterables. - -## অ্যাসিঙ্ক ইটারেটর - -অ্যাসিঙ্ক্রোনাস ইটারেটর অনেকটা সাধারণ ইটারেটরের মত, শুধু কিছু সিনট্যাক্সের পার্থক্য আছে। +যদি আপনি ইটারেটর নিয়ে আরো বিস্তারিত জানতে চান দয়া করে এটি দেখুন [ইটারেবল চ্যাপ্টার](info:iterable)। -একটি "সাধারণ" ইটারেবল অবজেক্ট, যা আমরা এই অধ্যায়ে জানতে পারি , দেখতে অনেকটা এমনঃ +## অ্যাসিঙ্ক ইটারেবল -```js run -let range = { - from: 1, - to: 5, +যখন আমরা কোন মান অ্যাসিঙ্ক্রোনাসলি পেতে চাই তখন আমাদের অ্যাসিঙ্ক ইটারেটর লাগে: অনেকটা `setTimeout` বা এই ধরণের অন্যান্য ফাংশনের জন্য। - // for..of range কে কল করা হলে সবার শুরুতে এই মেথডটি এক্সিকিউট হবে -*!* - [Symbol.iterator]() { // called once, in the beginning of for..of -*/!* - // ...এটি রিটার্ন করে ইটারেটর অবজেক্ট: - // পরবর্তীতে, for..of শুধু অবজেক্টির সাথে কাজ করে এবং এর মাধ্যমে আমরা মান গুলো জানতে পারি - // পরবর্তী মানটি next() এর মাধ্যমে জানা যায় - return { - current: this.from, - last: this.to, +সাধারণত আমরা আমাদের নেটওয়ার্ক রিকুয়েস্টে পরবর্তী মানটি পাঠাতে এমন অবজেক্ট লাগে, পরবর্তীতে আমরা ব্যবহারিক উদাহরণের মাধ্যমে আরো ভালোভাবে বুঝব। - // for..of লুপের প্রতিবার ইটারেশনে next() কল হয় -*!* - next() { // (2) - // এটি রিটার্ন করবে একটি অবজেক্ট {done:.., value :...} -*/!* - if (this.current <= this.last) { - return { done: false, value: this.current++ }; - } else { - return { done: true }; - } - } - }; - } -}; +অ্যাসিঙ্ক্রোনাসলি ইটারেটরেবল অবজেক্ট তৈরি করতে: -for(let value of range) { - alert(value); // 1 তারপর 2, তারপর 3, তারপর 4, তারপর 5 -} -``` -যদি আপনি সাধারণ ইটারেটর নিয়ে আরো বিস্তারিত জানতে চান দয়া করে এটি দেখুন [ইটারেবল চ্যাপ্টার](info:iterable)। +১. আমাদের `Symbol.iterator` এর পরিবর্তে `Symbol.asyncIterator` ব্যবহার করা লাগবে। +২. `next()` অবশ্যই একটি প্রমিস রিটার্ন করবে (পরবর্তী মানের জন্য এটি fulfilled হবে)। + - `async` কিওয়ার্ডটি এটি হ্যান্ডল করবে, সহজেই আমরা লিখতে পারি `async next()`। +৩. এইধরনের অবজেক্ট ইটারেট করতে, আমরা ব্যবহার করব `for await (let item of iterable)` লুপ। + - `await` কিওয়ার্ডটি নোট করুন। -অ্যাসিঙ্ক্রোনাসলি ইটারেটরেবল অবজেক্ট তৈরি করতে: -1. আমাদের `Symbol.iterator` এর পরিবর্তে `Symbol.asyncIterator` ব্যবহার করা লাগবে। -2. `next()` অবশ্যই একটি প্রমিস রিটার্ন করবে। -3. এইধরনের অবজেক্ট ইটারেট করতে, আমরা ব্যবহার করব `for await (let item of iterable)` লুপ। +চলুন আগেরটির মত একটি ইটারেটরেবল `range` অবজেক্ট তৈরি করি কিন্তু এটি অ্যাসিঙ্ক্রোনাসলি প্রতি সেকেন্ডে একটি মান রিটার্ন করবে। -চলুন আগেরটির মত একটি ইটারেটরেবল `range` অবজেক্ট তৈরি করি কিন্তু এটি অ্যাসিঙ্ক্রোনাসলি প্রতি সেকেন্ডে একটি মান রিটার্ন করবেঃ +আমাদের পূর্বের কোডের কিছু জায়গায় পরিবর্তন লাগবে: ```js run let range = { from: 1, to: 5, - // for await..of কে কল করা হলে সবার শুরুতে এই মেথডটি এক্সিকিউট হবে *!* [Symbol.asyncIterator]() { // (1) */!* - // ...এটি রিটার্ন করে ইটারেটর অবজেক্ট: - // পরবর্তীতে, for await..of শুধু অবজেক্টির সাথে কাজ করে এবং এর মাধ্যমে আমরা মান গুলো জানতে পারি - // পরবর্তী মানটি next() এর মাধ্যমে জানা যায় return { current: this.from, last: this.to, - //for await..of লুপের প্রতিবার ইটারেশনে next() কল হয় *!* async next() { // (2) - // এটি রিটার্ন করবে একটি অবজেক্ট {done:.., value :...} - // (স্বয়ংক্রিয়ভাবে এটি অ্যাসিঙ্ক এর মাধ্যমে একটি প্রমিসে র‍্যাপ হয়) */!* *!* - // অ্যাসিঙ্ক কাজগুলো আমরা এওয়েট এর ভিতর করতে পারিঃ + // নোট: আমরা async next এ "await" ব্যবহার করতে পারি: await new Promise(resolve => setTimeout(resolve, 1000)); // (3) */!* @@ -163,12 +121,12 @@ let range = { আমরা দেখতে পাচ্ছি এটির স্ট্রাকচার অনেকটা সাধারণ ইটারেটরের মতঃ -1. একটি অ্যাসিঙ্ক্রোনাসলি ইটারেটরেবল অবজেক্ট তৈরি করতে `Symbol.asyncIterator` `(1)` মেথডটি অবশ্যই লাগবে। -2. মেথডটি `next()` মেথডে একটি প্রমিস এর মাধ্যমে অবজেক্টটি রিটার্ন করে `(2)`। -3. The `next()` method doesn't have to be `async`, it may be a regular method returning a promise, but `async` allows to use `await`, so that's convenient. Here we just delay for a second `(3)`। -4. ইটারেটের জন্য আমরা `for await(let value of range)` `(4)` ব্যবহার করি, লুপে "for" এর পর "await" ব্যবহার করুন। এটি প্রথমে কল করে `range[Symbol.asyncIterator]()` কে এবং পরে মানের জন্য `next()` কে। +১. একটি অ্যাসিঙ্ক্রোনাসলি ইটারেটরেবল অবজেক্ট তৈরি করতে `Symbol.asyncIterator` `(1)` মেথডটি অবশ্যই লাগবে। +২. মেথডটি `next()` মেথডে একটি প্রমিস এর মাধ্যমে অবজেক্টটি রিটার্ন করে `(2)`। +৩. The `next()` method doesn't have to be `async`, it may be a regular method returning a promise, but `async` allows to use `await`, so that's convenient. Here we just delay for a second `(3)`। +৪. ইটারেটের জন্য আমরা `for await(let value of range)` `(4)` ব্যবহার করি, লুপে "for" এর পর "await" ব্যবহার করুন। এটি প্রথমে কল করে `range[Symbol.asyncIterator]()` কে এবং পরে মানের জন্য `next()` কে। -ছোট একটি চিটশিট: +এখানে এদের পার্থক্য দেয়া হল: | | ইটারেটর | অ্যাসিঙ্ক ইটারেটর | |-------|-----------|-----------------| @@ -181,19 +139,23 @@ let range = { এটি সিঙ্ক্রোনাস ইটারেটরের একটি ফিচার, অ্যাসিঙ্ক্রোনাসের সাথে কাজ করে না। -উদাহরণস্বরূপ, এখানে স্প্রেড অপারেটর কাজ করবে নাঃ +উদাহরণস্বরূপ, এখানে স্প্রেড অপারেটর কাজ করবে না: ```js alert( [...range] ); // Error, no Symbol.iterator ``` -এটিই স্বাভাবিক কেননা এটি `Symbol.iterator` কে খুঁজে `for..of` এর মত `Symbol.asyncIterator` কে না। +এটিই স্বাভাবিক, কেননা এটি `Symbol.iterator` এর সাথে কাজ করে, `Symbol.asyncIterator` এর সাথে করে না। + +`for..of` এর জন্যও এটি কাজ করবে না: কেননা `await`, `Symbol.iterator` এর সাথে কাজ করে না। ```` -## অ্যাসিঙ্ক জেনারেটর +## পুনরায় জেনারেটরস + +চলুন আবার জেনারেটর ব্যবহার করি, এটির মাধ্যমে আমরা ইটারেশনের কোডকে আরো সংক্ষিপ্ত করতে পারি। বেশিরভাগ ক্ষেত্রে আমরা ইটারেবল অবজেক্ট তৈরিতে জেনারেটর ব্যবহার করি, বিস্তারিত এই অধ্যায়ে [](info:generators)। -ইতোমধ্যে আমরা জানি জাভাস্ক্রিপ্ট জেনারেটর সাপোর্ট করে যা ইটারেবল। +জেনারেটর গুলো `function*` এভাবে লিখতে পারি এবং `yield` ব্যবহার করি মান জেনারেট করতে, তারপর `for..of` এদের ইটারেট করতে পারি। -চলুন একটি সিক্যুয়েন্স জেনারেটরকে কল করি যা এই অধ্যায়ে [](info:generators) জেনেছিলাম। এটি একটি সিক্যুয়েন্স মান তৈরি করে `start` হতে `end` পর্যন্তঃ +উদাহরণটিতে একটি সিক্যুয়েন্স মান তৈরি করে `start` হতে `end` পর্যন্ত: ```js run function* generateSequence(start, end) { @@ -207,11 +169,54 @@ for(let value of generateSequence(1, 5)) { } ``` -সাধারণ জেনারেটরে আমরা `await` ব্যবহার করতে পারি না। সকল মান সিঙ্ক্রোনাসলি আসেঃ এখানে `for..of` এ কোন লাইনে এ ডিলে হয় না, এটি একটি সিঙ্ক্রোনাস কন্সট্রাক্ট। +ইতোমধ্যে আমরা জানি, ইটারেবল অবজেক্ট তৈরিতে, আমাদের অবশ্যই `Symbol.iterator` লাগবে। -কিন্ত যদি আমরা জেনারেটর বডিতে `await` ব্যবহার করি কি হবে? যেমন নেটওয়ার্ক রিকুয়েস্টের সাথে কাজ করার জন্য। +```js +let range = { + from: 1, + to: 5, +*!* + [Symbol.iterator]() { + return + } +*/!* +} +``` -কোন সমস্যা নেই, আমরা এভাবে `async` কে প্রিপেন্ড করে নিতে পারিঃ +`Symbol.iterator` এর অন্যতম প্রয়োগ হয় জেনারেটরে, এর মাধ্যমে আমরা কোডকে সংক্ষিপ্ত করতে পারি: + +```js run +let range = { + from: 1, + to: 5, + + *[Symbol.iterator]() { // a shorthand for [Symbol.iterator]: function*() + for(let value = this.from; value <= this.to; value++) { + yield value; + } + } +}; + +for(let value of range) { + alert(value); //1, তারপর 2, তারপর 3, তারপর 4, তারপর 5 +} +``` + +আরো বিস্তারিত জানতে এই অধ্যায়টি দেখুন [](info:generators)। + +সাধারণ জেনারেটরে আমরা `await` ব্যবহার করতে পারি না। সকল মান সিঙ্ক্রোনাসলি আসে, এখানে `for..of` এ কোন লাইনে এ ডিলে হয় না, এটি একটি সিঙ্ক্রোনাস কন্সট্রাক্ট। + +যদি আমরা মানগুলো অ্যাসিঙ্ক্রোনাসলি পেতে চাই যেমন নেটওয়ার্ক রিকুয়েস্টে তখন কি হবে? + +চলুন অ্যাসিঙ্ক্রোনাস জেনারেটরের মাধ্যমে আমরা এটি ইমপ্লিমেন্ট করি। + +## অ্যাসিঙ্ক জেনারেটর + +আমাদের অ্যাপ্লিকেশনগুলোতে যখন আমরা অবজেক্ট এর মানসমূহকে অ্যাসিঙ্ক্রোনাসলি জেনারেট করতে চায়, তখন আমরা অ্যাসিঙ্ক্রোনাস জেনারেটর ব্যবহার করতে চায়। + +এর সিনট্যাক্স সহজবোধ্য: `function*` এর পূর্বে `async` কিওয়ার্ড লিখা লাগবে। এভাবেই অ্যাসিঙ্ক্রোনাস জেনারেটর লিখা যায়। + +এবং একে `for await (...)` ইটারেট করব: ```js run *!*async*/!* function* generateSequence(start, end) { @@ -219,7 +224,7 @@ for(let value of generateSequence(1, 5)) { for (let i = start; i <= end; i++) { *!* - // হুররে, আমরা এওয়েট ব্যবহার করতে পারছি! + // Wow, can use await! await new Promise(resolve => setTimeout(resolve, 1000)); */!* @@ -232,73 +237,41 @@ for(let value of generateSequence(1, 5)) { let generator = generateSequence(1, 5); for *!*await*/!* (let value of generator) { - alert(value); // 1, তারপর 2, তারপর 3, তারপর 4, তারপর 5 + alert(value); //1, তারপর 2, তারপর 3, তারপর 4, তারপর 5(প্রতিটির মধ্যে ১ সেকেন্ড পার্থক্য থাকে) } })(); ``` -এখন আমাদের অ্যাসিঙ্ক জেনারেটর আছে যা `for await...of` এর দ্বারা ইটারেটবল। +জেনারেটরটি অ্যাসিঙ্ক্রোনাস হওয়ায় আমরা এর মধ্যে `await`, `promise` এবং নেটওয়ার্ক কল ইত্যাদি করতে পারি। -এটি খুব সহজ, আমরা একটি `async` যুক্ত করি এবং জেনারেটরের মধ্যে প্রমিস অথবা অন্যান্য অ্যাসিঙ্ক ফাংশনের এর উপর ভিত্তি করে `await` ব্যবহার করতে পারি। +````smart header="এদের ইন্টারনাল পার্থক্য" +টেকনিক্যালি, জেনারেটর এবং অ্যাসিঙ্ক জেনারেটরের মধ্যে ইন্টারনাল ডিফারেন্স আছে। -টেকনিক্যালি, অ্যাসিঙ্ক জেনারেটরের আরেকটি পার্থক্য হল এখন `generator.next()` এই মেথডটিও অ্যাসিঙ্ক্রোনাস, যা একটি প্রমিস রিটার্ন করে। +অ্যাসিঙ্ক জেনারেটরে, `generator.next()` মেথডটি অ্যাসিঙ্ক্রোনাস, এটি `promise` রিটার্ন করে। -সাধারণ জেনারেটরে আমরা মান এভাবে পাই `result = generator.next()`. কিন্তু অ্যাসিঙ্ক জেনারেটরে মান পেতে আমাদের `await` যুক্ত করতে হবে, এভাবেঃ +সাধারণ জেনারেটরে আমরা মান এভাবে পাই `result = generator.next()`. কিন্তু অ্যাসিঙ্ক জেনারেটরে মান পেতে আমাদের `await` যুক্ত করতে হবে, এভাবে: ```js result = await generator.next(); // result = {value: ..., done: true/false} ``` -That's why async generators work with `for await...of`. +এজন্য অ্যাসিঙ্ক জেনারেটর `for await...of` লুপ লাগে। ```` -## অ্যাসিঙ্ক ইটারেটবল। +### অ্যাসিঙ্ক ইটারেবল রেঞ্জ -ইতোমধ্যে আমরা জেনেছি ইটারেবল অবজেক্ট তৈরি করতে আমাদের `Symbol.iterator` যুক্ত করতে হয়। +সাধারণত জেনারেটরে `Symbol.iterator` ব্যবহার করে ইটারেশন কোডকে আমরা সংক্ষিপ্ত করতে পারি। -```js -let range = { - from: 1, - to: 5, -*!* - [Symbol.iterator]() { - return - } -*/!* -} -``` +অনুরূপভাবে, অ্যাসিঙ্ক জেনারেটরে `Symbol.asyncIterator` ব্যবহার করে অ্যাসিঙ্ক্রোনাস ইটারেশন ইমপ্লিমেন্ট করতে পারি। -`Symbol.iterator` এর মাধ্যমে জেনারেটর রিটার্নের জন্য এর একটি কমন প্রাকটিস হল আগের উদাহরণের মত `next` এর মাধ্যমে অবজেক্ট রিটার্ন করা। - -চলুন এই অধ্যায়ের [](info:generators) উদাহরনটি আবার কল করিঃ +যেমন, আমরা `range` এর মানগুলো প্রতি সেকেন্ড হিসেব করে অ্যাসিঙ্ক্রোনাসলি জেনারেট করতে পারি, এজন্য `Symbol.iterator` এর বদলে `Symbol.asyncIterator` লাগবে: ```js run let range = { from: 1, to: 5, - *[Symbol.iterator]() { // [Symbol.iterator]: function*() এর সংক্ষিপ্তরূপ - for(let value = this.from; value <= this.to; value++) { - yield value; - } - } -}; - -for(let value of range) { - alert(value); // 1, তারপর 2, তারপর 3, তারপর 4, তারপর 5 -} -``` - -এখানে `range` কাস্টম অবজেক্টটি একটি ইটারেবল, এবং `*[Symbol.iterator]` জেনারেটরটি দ্বারা মানগুলো দেখাতে লজিক প্রয়োগ করি। - -যদি আমরা জেনারেটরে অ্যাসিঙ্ক অ্যাকশন যুক্ত করতে চাই আমাদের `Symbol.iterator` এর পরিবর্তে async `Symbol.asyncIterator` ব্যবহার করতে হবেঃ - -```js run -let range = { - from: 1, - to: 5, - - // this line is same as [Symbol.asyncIterator]: async function*() { + // [Symbol.asyncIterator]: async function*() { এই লাইনটি এর অনুরূপ *!* async *[Symbol.asyncIterator]() { */!* @@ -323,31 +296,37 @@ let range = { এখন মানগুলো ১ সেকেন্ড পর পর আসবে। -## একটি বাস্তবিক উদাহরণ +```smart +ট্যাকনিক্যালি, অবজেক্টটিতে `Symbol.iterator` এবং `Symbol.asyncIterator` উভয়ই ব্যবহার করতে পারি, এরা উভয়ই সিঙ্ক্রোনাসলি (`for..of`) এবং অ্যাসিঙ্ক্রোনাসলি (`for await..of`) ইটারেবল হবে। -এ পর্যন্ত আমরা কিছু সাধারন উদাহরণ এর সাহায্যে বেসিক ব্যাপারগুলো দেখলাম। চলুন এখন আমরা একটি বাস্তবিক ব্যবহার দেখি। +বাস্তবে, এভাবে না করায় উচিত। +``` + +## একটি বাস্তবিক উদাহরণ: paginated data + +আমরা অনেক উদাহরণ দেখার সাহায্যে অ্যাসিঙ্ক ইটারেটর এবং জেনারেটর বুঝেছি। চলুন একটি বাস্তবিক উদাহরণ দেখি। অনলাইনে অনেক সার্ভিস আছে যারা পেজিনেটেড ডাটা সরবরাহ করে। উদাহরণস্বরূপ, যখন আমাদের ইউজারদের একটি লিস্ট দরকার হয় এটি "এক পেজের" জন্য একটি রিকুয়েস্টে প্রি-ডিফাইন্ড (যেমনঃ ১০০ জন ইউজারের) ডাটা রিটার্ন করে , এবং পরবর্তী পেজে যাওয়ার জন্য একটি URL প্রদান করে। -এটি একটি কমন প্যাটার্ন। এটি শুধু ইউজারের জন্য না যেকোন ধরনের লিস্টের জন্য হতে পারে। উদাহরণস্বরূপ, গিটহাব হতে আমরা পেজিনেটেড উপায়ে কমিট নিয়ে আসতে পারিঃ +এটি একটি কমন প্যাটার্ন। এটি শুধুমাত্র ইউজারের জন্য না, যেকোন কিছু হতে পারে। + +উদাহরণস্বরূপ, গিটহাব হতে আমরা পেজিনেটেড উপায়ে কমিট নিয়ে আসতে পারি: -- এই জন্য আমাদের এই `https://api.github.com/repos//commits` URL এ একটি রিকুয়েস্ট করা লাগবে। +- এই জন্য আমাদের এই `https://api.github.com/repos//commits` URL এ একটি `fetch` রিকুয়েস্ট করা লাগবে। - এটি জেসন ফরম্যাটে ৩০ টি কমিট রেসপন্ড করে, এবং পরবর্তী পেজে যাওয়ার জন্য `Link` হেডারের মাধ্যমে একটি লিঙ্ক প্রদান করে। - তারপর আমরা পরবর্তী কমিটগুলোর জন্য লিঙ্কটির মাধ্যমে আরো রিকুয়েস্ট পাঠাতে পারি, এভাবে চলতে থাকবে। -এখন আমরা একটি সিম্পল API চাই: যেটি কমিটগুলোর একটি ইটারেবল অবজেক্ট হয়, তো আমরা এভাবে করতে পারিঃ +আমরা কমিট নিয়ে আসার জন্য একটি `fetchCommits(repo)` ফাংশন তৈরি করি, যা প্রয়োজনমত রিকুয়েস্ট তৈরি করে। এবং পেজিনেশনের সকল ব্যাপার এটির মাধ্যমে নিয়ন্ত্রিত হয়। এটি একটি সিম্পল `for await..of`। -```js -let repo = 'javascript-tutorial/en.javascript.info'; // যে গিটহাব রিপোজেটরী থেকে কমিট নিয়ে আসব +এখন আমরা একটি সিম্পল API চাই: যেটি কমিটগুলোর একটি ইটারেবল অবজেক্ট হয়, তো আমরা এভাবে করতে পারি: -for await (let commit of fetchCommits(repo)) { +```js +for await (let commit of fetchCommits("username/repository")) { // কমিটগুলো প্রসেস করি } ``` -আমরা কমিট নিয়ে আসার জন্য একটি `fetchCommits(repo)` ফাংশন তৈরি করি, যা প্রয়োজনমত রিকুয়েস্ট তৈরি করে। এবং পেজিনেশনের সকল ব্যাপার এটির মাধ্যমে নিয়ন্ত্রিত হয়। এটি একটি সিম্পল `for await..of`। - -অ্যাসিঙ্ক জেনারেটরের মাধ্যমে আমরা সহজেই এটি তৈরি করতে পারিঃ +চলুন অ্যাসিঙ্ক জেনারেটরটি ইমপ্লিমেন্ট করি: ```js async function* fetchCommits(repo) { @@ -373,11 +352,12 @@ async function* fetchCommits(repo) { } ``` +এটি কিভাবে কাজ করছে বিস্তারিত দেখি: -1. আমরা রিমোট URL থেকে কিছু ডাউনলোডের জন্য ব্রাউজারের [fetch](info:fetch) মেথডটি ব্যবহার করতে পারি। এটির মাধ্যমে আমরা অথোরাইজেশন এবং অন্যান্য হেডার পাস করতে পারি -- গিটহাব API এ রিকুয়েস্টের জন্য আমাদের `User-Agent` হেডারটি পাঠানো প্রয়োজন -2. `fetch` এর মাধ্যমে আমরা একটি জেসন অবজেক্ট পাই, যা `fetch`এর একটি নির্দিষ্ট মেথড। -3. আমরা পরবর্তী পেজের URL টি রেস্পন্সের `Link` হেডার হতে পাই। এটি একটি স্পেশাল ফরম্যাটে থাকে তাই আমরা রেগুলার এক্সপ্রেশন ব্যবহারের এর মাধ্যমে পরবর্তী পেজের লিঙ্কটি পায়। পরবর্তী পেজের URL টি দেখতে এমন হয় `https://api.github.com/repositories/93253246/commits?page=2`। এটি গিটহাবের মাধ্যমে জেনারেট হয়। -4. তারপর আমরা `yield` এর মাধ্যমে কমিট গুলো রিসিভ করি এবং যখন এটি শেষ হয়, `while(url)` লুপ আবার রান হয় এবং এর ফলে আরো রিকুয়েস্ট জেনারেট হয়। +১. আমরা রিমোট URL থেকে কিছু ডাউনলোডের জন্য ব্রাউজারের [fetch](info:fetch) মেথডটি ব্যবহার করতে পারি। এটির মাধ্যমে আমরা অথোরাইজেশন এবং অন্যান্য হেডার পাস করতে পারি -- গিটহাব API এ রিকুয়েস্টের জন্য আমাদের `User-Agent` হেডারটি পাঠানো প্রয়োজন +২. `fetch` এর মাধ্যমে আমরা একটি জেসন অবজেক্ট পাই, যা `fetch`এর একটি নির্দিষ্ট মেথড। +৩. আমরা পরবর্তী পেজের URL টি রেস্পন্সের `Link` হেডার হতে পাই। এটি একটি স্পেশাল ফরম্যাটে থাকে তাই আমরা রেগুলার এক্সপ্রেশন ব্যবহারের এর মাধ্যমে পরবর্তী পেজের লিঙ্কটি পায়। পরবর্তী পেজের URL টি দেখতে এমন হয় `https://api.github.com/repositories/93253246/commits?page=2`। এটি গিটহাবের মাধ্যমে জেনারেট হয়। +৪. তারপর আমরা `yield` এর মাধ্যমে কমিট গুলো রিসিভ করি এবং যখন এটি শেষ হয়, `while(url)` লুপ আবার রান হয় এবং এর ফলে আরো রিকুয়েস্ট জেনারেট হয়। উদাহরণস্বরূপ (কনসোলে কমিটের অথরের নাম দেখায়): @@ -423,5 +403,4 @@ async function* fetchCommits(repo) { ওয়েব ডেভলাপমেন্টে আমাদের প্রায়শই ছোট ছোট করে ডাটা স্ট্রীমের দরকার হয়। উদাহরনস্বরূন, একটি বড় ফাইল ডাউনলোড বা আপলোডের জন্য। -আমরা এই ধরনের ডাটার জন্য অ্যাসিঙ্ক জেনারেটর ব্যবহার করতে পারি। বিঃদ্রঃ কিছু এনভাইরনমেন্টে যেমন ব্রাউজারে একটি Streams API আছে, এটি ডাটাকে এক স্ট্রীম থেকে অন্য স্ট্রীমে পাঠাতে একটি বিশেষ ইন্টারফেস দেয় (যেমনঃ এক জায়গা হতে ডাউনলোড করে সাথে সাথে অন্য আরেক জায়গায় পাঠানো)। - +আমরা এই ধরনের ডাটার জন্য অ্যাসিঙ্ক জেনারেটর ব্যবহার করতে পারি। বিঃদ্রঃ কিছু এনভাইরনমেন্টে যেমন ব্রাউজারে একটি Streams API আছে, এটি ডাটাকে এক স্ট্রীম থেকে অন্য স্ট্রীমে পাঠাতে একটি বিশেষ ইন্টারফেস দেয় (যেমনঃ এক জায়গা হতে ডাউনলোড করে সাথে সাথে অন্য আরেক জায়গায় পাঠানো)। \ No newline at end of file