JavaScriptã®éåæã€ãã¬ãŒã¿ãã¿ãŒã³ãæ¢æ±ããå¹ççãªã¹ããªãŒã åŠçãããŒã¿å€æããªã¢ã«ã¿ã€ã ã¢ããªã±ãŒã·ã§ã³éçºãå®çŸããŸãã
JavaScriptã¹ããªãŒã åŠçïŒéåæã€ãã¬ãŒã¿ãã¿ãŒã³ã®ç¿åŸ
çŸä»£ã®ãŠã§ãããã³ãµãŒããŒãµã€ãéçºã«ãããŠãå€§èŠæš¡ãªããŒã¿ã»ããããªã¢ã«ã¿ã€ã ã®ããŒã¿ã¹ããªãŒã ãæ±ãããšã¯äžè¬çãªèª²é¡ã§ããJavaScriptã¯ã¹ããªãŒã åŠçã®ããã®åŒ·åãªããŒã«ãæäŸããŠãããéåæã€ãã¬ãŒã¿ã¯éåæããŒã¿ãããŒãå¹ççã«ç®¡çããããã®éèŠãªãã¿ãŒã³ãšããŠç»å ŽããŸããããã®ããã°èšäºã§ã¯ãJavaScriptã«ãããéåæã€ãã¬ãŒã¿ã®ãã¿ãŒã³ãæãäžãããã®å©ç¹ãå®è£ ããããŠå®è·µçãªå¿çšã«ã€ããŠæ¢æ±ããŸãã
éåæã€ãã¬ãŒã¿ãšã¯äœãïŒ
éåæã€ãã¬ãŒã¿ã¯ãéåæããŒã¿ãœãŒã¹ãæ±ãããã«èšèšããããæšæºçãªJavaScriptã€ãã¬ãŒã¿ãããã³ã«ã®æ¡åŒµã§ããåæçã«å€ãè¿ãéåžžã®ã€ãã¬ãŒã¿ãšã¯ç°ãªããéåæã€ãã¬ãŒã¿ã¯ã·ãŒã±ã³ã¹å ã®æ¬¡ã®å€ã§è§£æ±ºããããããã¹ïŒPromiseïŒãè¿ããŸãããã®éåæçãªæ§è³ªã«ããããããã¯ãŒã¯ãªã¯ãšã¹ãããã¡ã€ã«èªã¿èŸŒã¿ãããŒã¿ããŒã¹ã¯ãšãªãªã©ãæéçµéãšå ±ã«å°çããããŒã¿ãæ±ãã®ã«çæ³çã§ãã
äž»èŠãªæŠå¿µïŒ
- éåæã€ãã©ãã«ïŒAsync IterableïŒïŒ `Symbol.asyncIterator`ãšããååã®ã¡ãœãããæã¡ãéåæã€ãã¬ãŒã¿ãè¿ããªããžã§ã¯ãã
- éåæã€ãã¬ãŒã¿ïŒAsync IteratorïŒïŒ `next()`ã¡ãœãããå®çŸ©ãããªããžã§ã¯ãããã®ã¡ãœããã¯ãéåžžã®ã€ãã¬ãŒã¿ãšåæ§ã«`value`ãš`done`ããããã£ãæã€ãªããžã§ã¯ãã§è§£æ±ºããããããã¹ãè¿ããŸãã
- `for await...of`ã«ãŒãïŒ éåæã€ãã©ãã«ãå埩åŠçããã®ãç°¡çŽ åããèšèªæ§æã
ãªãã¹ããªãŒã åŠçã«éåæã€ãã¬ãŒã¿ã䜿çšããã®ãïŒ
éåæã€ãã¬ãŒã¿ã¯ãJavaScriptã§ã®ã¹ããªãŒã åŠçã«ãããŠããã€ãã®å©ç¹ãæäŸããŸãïŒ
- ã¡ã¢ãªå¹çïŒ ããŒã¿ã»ããå šäœãäžåºŠã«ã¡ã¢ãªã«èªã¿èŸŒãã®ã§ã¯ãªãããã£ã³ã¯ïŒå¡ïŒã§ããŒã¿ãåŠçããŸãã
- å¿çæ§ïŒ éåæçã«ããŒã¿ãåŠçããããšã§ãã¡ã€ã³ã¹ã¬ããã®ããããã³ã°ãåé¿ããŸãã
- æ§æå¯èœæ§ïŒ è€æ°ã®éåææäœãé£çµããŠãè€éãªããŒã¿ãã€ãã©ã€ã³ãäœæããŸãã
- ãšã©ãŒãã³ããªã³ã°ïŒ éåææäœã®ããã®å ç¢ãªãšã©ãŒãã³ããªã³ã°ã¡ã«ããºã ãå®è£ ããŸãã
- ããã¯ãã¬ãã·ã£ãŒïŒèå§ïŒç®¡çïŒ ããŒã¿ãæ¶è²»ãããé床ãå¶åŸ¡ããã³ã³ã·ã¥ãŒããå§åãããã®ãé²ããŸãã
éåæã€ãã¬ãŒã¿ã®äœæ
JavaScriptã§éåæã€ãã¬ãŒã¿ãäœæããã«ã¯ãããã€ãã®æ¹æ³ããããŸãïŒ
1. éåæã€ãã¬ãŒã¿ãããã³ã«ãæåã§å®è£ ãã
ããã«ã¯ã`Symbol.asyncIterator`ã¡ãœãããæã€ãªããžã§ã¯ããå®çŸ©ãããã®ã¡ãœããã`next()`ã¡ãœãããæã€ãªããžã§ã¯ããè¿ãããã«ããŸãã`next()`ã¡ãœããã¯ãã·ãŒã±ã³ã¹ã®æ¬¡ã®å€ã§è§£æ±ºããããããã¹ããŸãã¯ã·ãŒã±ã³ã¹ãå®äºãããšãã«`{ value: undefined, done: true }`ã§è§£æ±ºããããããã¹ãè¿ãã¹ãã§ãã
class Counter {
constructor(limit) {
this.limit = limit;
this.count = 0;
}
async *[Symbol.asyncIterator]() {
while (this.count < this.limit) {
await new Promise(resolve => setTimeout(resolve, 500)); // éåæçãªé
å»¶ãã·ãã¥ã¬ãŒã
yield this.count++;
}
}
}
async function main() {
const counter = new Counter(5);
for await (const value of counter) {
console.log(value); // åºå: 0, 1, 2, 3, 4 (åå€ã®éã«500msã®é
å»¶ãã)
}
console.log("Done!");
}
main();
2. éåæãžã§ãã¬ãŒã¿é¢æ°ã䜿çšãã
éåæãžã§ãã¬ãŒã¿é¢æ°ã¯ãéåæã€ãã¬ãŒã¿ãäœæããããã®ããç°¡æœãªæ§æãæäŸããŸãããããã¯`async function*`æ§æã䜿çšããŠå®çŸ©ããã`yield`ããŒã¯ãŒãã䜿çšããŠéåæã«å€ãçæããŸãã
async function* generateSequence(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // éåæçãªé
å»¶ãã·ãã¥ã¬ãŒã
yield i;
}
}
async function main() {
const sequence = generateSequence(1, 3);
for await (const value of sequence) {
console.log(value); // åºå: 1, 2, 3 (åå€ã®éã«500msã®é
å»¶ãã)
}
console.log("Done!");
}
main();
3. æ¢åã®éåæã€ãã©ãã«ã倿ãã
`map`ã`filter`ã`reduce`ã®ãããªé¢æ°ã䜿çšããŠãæ¢åã®éåæã€ãã©ãã«ã倿ã§ããŸãããããã®é¢æ°ã¯ãå ã®ã€ãã©ãã«ã®ããŒã¿ãåŠçããæ°ããéåæã€ãã©ãã«ãäœæããããã«ãéåæãžã§ãã¬ãŒã¿é¢æ°ã䜿çšããŠå®è£ ã§ããŸãã
async function* map(iterable, transform) {
for await (const value of iterable) {
yield await transform(value);
}
}
async function* filter(iterable, predicate) {
for await (const value of iterable) {
if (await predicate(value)) {
yield value;
}
}
}
async function main() {
async function* numbers() {
yield 1;
yield 2;
yield 3;
}
const doubled = map(numbers(), async (x) => x * 2);
const even = filter(doubled, async (x) => x % 2 === 0);
for await (const value of even) {
console.log(value); // åºå: 2, 4, 6
}
console.log("Done!");
}
main();
äžè¬çãªéåæã€ãã¬ãŒã¿ã®ãã¿ãŒã³
å¹ççãªã¹ããªãŒã åŠçã®ããã«ãéåæã€ãã¬ãŒã¿ã®èœåãæŽ»çšããããã€ãã®äžè¬çãªãã¿ãŒã³ããããŸãïŒ
1. ãããã¡ãªã³ã°
ãããã¡ãªã³ã°ã¯ãéåæã€ãã©ãã«ããè€æ°ã®å€ããããã¡ã«åéããŠããåŠçããããšã§ããããã«ãããéåææäœã®æ°ãæžãããããã©ãŒãã³ã¹ãåäžãããããšãã§ããŸãã
async function* buffer(iterable, bufferSize) {
let buffer = [];
for await (const value of iterable) {
buffer.push(value);
if (buffer.length === bufferSize) {
yield buffer;
buffer = [];
}
}
if (buffer.length > 0) {
yield buffer;
}
}
async function main() {
async function* numbers() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
const buffered = buffer(numbers(), 2);
for await (const value of buffered) {
console.log(value); // åºå: [1, 2], [3, 4], [5]
}
console.log("Done!");
}
main();
2. ã¹ããããªã³ã°
ã¹ããããªã³ã°ã¯ãéåæã€ãã©ãã«ããå€ãåŠçãããã¬ãŒããå¶éããŸããããã«ãããã³ã³ã·ã¥ãŒããå§åãããã®ãé²ããã·ã¹ãã å šäœã®å®å®æ§ãåäžãããããšãã§ããŸãã
async function* throttle(iterable, delay) {
for await (const value of iterable) {
yield value;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
async function main() {
async function* numbers() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
const throttled = throttle(numbers(), 1000); // 1ç§ã®é
å»¶
for await (const value of throttled) {
console.log(value); // åºå: 1, 2, 3, 4, 5 (åå€ã®éã«1ç§ã®é
å»¶ãã)
}
console.log("Done!");
}
main();
3. ãããŠã³ã¹
ãããŠã³ã¹ã¯ãäžå®ã®éã¢ã¯ãã£ãæéã®åŸã«ã®ã¿å€ãåŠçãããããšãä¿èšŒããŸããããã¯ãæ€çŽ¢ããã¯ã¹ã§ã®ãŠãŒã¶ãŒå ¥åã®åŠçãªã©ãäžéå€ãåŠçããããªãã·ããªãªã§åœ¹ç«ã¡ãŸãã
async function* debounce(iterable, delay) {
let timeoutId;
let lastValue;
for await (const value of iterable) {
lastValue = value;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
yield lastValue;
}, delay);
}
if (timeoutId) {
clearTimeout(timeoutId);
yield lastValue; // æåŸã®å€ãåŠç
}
}
async function main() {
async function* input() {
yield 'a';
await new Promise(resolve => setTimeout(resolve, 200));
yield 'ab';
await new Promise(resolve => setTimeout(resolve, 100));
yield 'abc';
await new Promise(resolve => setTimeout(resolve, 500));
yield 'abcd';
}
const debounced = debounce(input(), 300);
for await (const value of debounced) {
console.log(value); // åºå: abcd
}
console.log("Done!");
}
main();
4. ãšã©ãŒãã³ããªã³ã°
å ç¢ãªãšã©ãŒãã³ããªã³ã°ã¯ãã¹ããªãŒã åŠçã«äžå¯æ¬ ã§ããéåæã€ãã¬ãŒã¿ã䜿çšãããšãéåææäœäžã«çºçãããšã©ãŒããã£ããããŠåŠçã§ããŸãã
async function* processData(iterable) {
for await (const value of iterable) {
try {
// åŠçäžã«èµ·ãããããšã©ãŒãã·ãã¥ã¬ãŒã
if (value === 3) {
throw new Error("Processing error!");
}
yield value * 2;
} catch (error) {
console.error("Error processing value:", value, error);
yield null; // ãŸãã¯å¥ã®æ¹æ³ã§ãšã©ãŒãåŠç
}
}
}
async function main() {
async function* numbers() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
const processed = processData(numbers());
for await (const value of processed) {
console.log(value); // åºå: 2, 4, null, 8, 10
}
console.log("Done!");
}
main();
å®äžçã§ã®å¿çšäŸ
éåæã€ãã¬ãŒã¿ã®ãã¿ãŒã³ã¯ãããŸããŸãªå®äžçã®ã·ããªãªã§äŸ¡å€ããããŸãïŒ
- ãªã¢ã«ã¿ã€ã ããŒã¿ãã£ãŒãïŒ æ ªåŒåžå ŽããŒã¿ãã»ã³ãµãŒã®æž¬å®å€ããŸãã¯ãœãŒã·ã£ã«ã¡ãã£ã¢ã®ã¹ããªãŒã ã®åŠçã
- 倧容éãã¡ã€ã«ã®åŠçïŒ ãã¡ã€ã«å šäœãã¡ã¢ãªã«èªã¿èŸŒãŸãã«ã倧容éãã¡ã€ã«ããã£ã³ã¯ã§èªã¿èŸŒãã§åŠçãäŸãã°ããã€ãã®ãã©ã³ã¯ãã«ãã«ãããŠã§ããµãŒããŒã®ãã°ãã¡ã€ã«ã®åæã
- ããŒã¿ããŒã¹ã¯ãšãªïŒ ããŒã¿ããŒã¹ã¯ãšãªããã®çµæãã¹ããªãŒãã³ã°ãç¹ã«å€§èŠæš¡ãªããŒã¿ã»ãããé·æéå®è¡ãããã¯ãšãªã«æçšã§ããäŸãã°ãæ¥æ¬ã®æ±äº¬ã«ããããŒã¿ããŒã¹ããéèååŒãã¹ããªãŒãã³ã°ããããšãæ³åããŠãã ããã
- API飿ºïŒ ãã£ã³ã¯ãã¹ããªãŒã ã§ããŒã¿ãè¿ãAPIããã®ããŒã¿æ¶è²»ãäŸãã°ãã¢ã«ãŒã³ãã³ã®ããšãã¹ã¢ã€ã¬ã¹ã®éœåžã®1æéããšã®æŽæ°ãæäŸãã倩æ°APIãªã©ã
- ãµãŒããŒéä¿¡ã€ãã³ãïŒSSEïŒïŒ ãã©ãŠã¶ãNode.jsã¢ããªã±ãŒã·ã§ã³ã§ãµãŒããŒéä¿¡ã€ãã³ããåŠçãããµãŒããŒããã®ãªã¢ã«ã¿ã€ã æŽæ°ãå¯èœã«ããŸãã
éåæã€ãã¬ãŒã¿ vs. Observable (RxJS)
éåæã€ãã¬ãŒã¿ã¯éåæã¹ããªãŒã ãæ±ãããã®ãã€ãã£ããªæ¹æ³ãæäŸããŸãããRxJSïŒReactive Extensions for JavaScriptïŒã®ãããªã©ã€ãã©ãªã¯ããªã¢ã¯ãã£ãããã°ã©ãã³ã°ã®ããã®ããé«åºŠãªæ©èœãæäŸããŸãã以äžã«æ¯èŒã瀺ããŸãïŒ
æ©èœ | éåæã€ãã¬ãŒã¿ | RxJS Observable |
---|---|---|
ãã€ãã£ããµããŒã | ãã (ES2018+) | ãªã (RxJSã©ã€ãã©ãªãå¿ èŠ) |
ãªãã¬ãŒã¿ | éå®ç (ã«ã¹ã¿ã å®è£ ãå¿ èŠ) | è±å¯ (ãã£ã«ã¿ãªã³ã°ããããã³ã°ãããŒãžãªã©ã®ããã®çµã¿èŸŒã¿ãªãã¬ãŒã¿) |
ããã¯ãã¬ãã·ã£ãŒ | åºæ¬ç (æåã§å®è£ å¯èœ) | é«åºŠ (ãããã¡ãªã³ã°ããããããã¹ããããªã³ã°ãªã©ãããã¯ãã¬ãã·ã£ãŒãåŠçããããã®æŠç¥) |
ãšã©ãŒãã³ããªã³ã° | æå (Try/catchãããã¯) | çµã¿èŸŒã¿ (ãšã©ãŒãã³ããªã³ã°ãªãã¬ãŒã¿) |
ãã£ã³ã»ã« | æå (ã«ã¹ã¿ã ããžãã¯ãå¿ èŠ) | çµã¿èŸŒã¿ (ãµãã¹ã¯ãªãã·ã§ã³ç®¡çãšãã£ã³ã»ã«) |
åŠç¿æ²ç· | äœã (ããã·ã³ãã«ãªæŠå¿µ) | é«ã (ããè€éãªæŠå¿µãšAPI) |
ããåçŽãªã¹ããªãŒã åŠçã®ã·ããªãªããå€éšäŸåãé¿ãããå Žåã«ã¯éåæã€ãã¬ãŒã¿ãéžæããŠãã ãããè€éãªããŒã¿å€æãããã¯ãã¬ãã·ã£ãŒç®¡çããšã©ãŒãã³ããªã³ã°ãæ±ãå Žåã¯ç¹ã«ãããè€éãªãªã¢ã¯ãã£ãããã°ã©ãã³ã°ã®ããŒãºã«ã¯RxJSãæ€èšããŠãã ããã
ãã¹ããã©ã¯ãã£ã¹
éåæã€ãã¬ãŒã¿ãæ±ãéã«ã¯ã以äžã®ãã¹ããã©ã¯ãã£ã¹ãèæ ®ããŠãã ããïŒ
- ãšã©ãŒãé©åã«åŠçããïŒ æªåŠçã®äŸå€ãã¢ããªã±ãŒã·ã§ã³ãã¯ã©ãã·ã¥ãããã®ãé²ãããã«ãå ç¢ãªãšã©ãŒãã³ããªã³ã°ã¡ã«ããºã ãå®è£ ããŸãã
- ãªãœãŒã¹ã管çããïŒ éåæã€ãã¬ãŒã¿ãäžèŠã«ãªã£ãéã«ã¯ããã¡ã€ã«ãã³ãã«ãããŒã¿ããŒã¹æ¥ç¶ãªã©ã®ãªãœãŒã¹ãé©åã«è§£æŸããããã«ããŸãã
- ããã¯ãã¬ãã·ã£ãŒãå®è£ ããïŒ ç¹ã«å€§å®¹éã®ããŒã¿ã¹ããªãŒã ãæ±ãå Žåãã³ã³ã·ã¥ãŒããå§åãããã®ãé²ãããã«ããŒã¿ãæ¶è²»ãããé床ãå¶åŸ¡ããŸãã
- æ§æå¯èœæ§ãå©çšããïŒ éåæã€ãã¬ãŒã¿ã®æ§æå¯èœãªæ§è³ªã掻çšããŠãã¢ãžã¥ã©ãŒã§åå©çšå¯èœãªããŒã¿ãã€ãã©ã€ã³ãäœæããŸãã
- 培åºçã«ãã¹ãããïŒ éåæã€ãã¬ãŒã¿ãããŸããŸãªæ¡ä»¶äžã§æ£ããæ©èœããããšã確èªããããã«ãå æ¬çãªãã¹ããèšè¿°ããŸãã
çµè«
éåæã€ãã¬ãŒã¿ã¯ãJavaScriptã§éåæããŒã¿ã¹ããªãŒã ãæ±ãããã®åŒ·åã§å¹ççãªæ¹æ³ãæäŸããŸããåºæ¬çãªæŠå¿µãšäžè¬çãªãã¿ãŒã³ãçè§£ããããšã§ãéåæã€ãã¬ãŒã¿ã掻çšããŠããªã¢ã«ã¿ã€ã ã§ããŒã¿ãåŠçããã¹ã±ãŒã©ãã«ã§å¿çæ§ãé«ããä¿å®å¯èœãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãããªã¢ã«ã¿ã€ã ããŒã¿ãã£ãŒãã倧容éãã¡ã€ã«ããŸãã¯ããŒã¿ããŒã¹ã¯ãšãªãæ±ã£ãŠããå Žåã§ããéåæã€ãã¬ãŒã¿ã¯éåæããŒã¿ãããŒã广çã«ç®¡çããã®ã«åœ¹ç«ã¡ãŸãã
ãããªãæ¢æ±
- MDN Web Docs: for await...of
- Node.js Streams API: Node.js Stream
- RxJS: Reactive Extensions for JavaScript