JavaScriptã®éåæã€ãã¬ãŒã¿ãã«ããŒãscanãã«ã€ããŠæ·±ãæãäžãããã®æ©èœããŠãŒã¹ã±ãŒã¹ãéåæçޝèšåŠçã«ãããå©ç¹ãæ¢ããŸãã
JavaScriptéåæã€ãŠã¬ãŒã¿ãã«ããŒãscanãïŒéåæã®çޝèšåŠç
éåæããã°ã©ãã³ã°ã¯ãç¹ã«ãããã¯ãŒã¯ãªã¯ãšã¹ãããã¡ã€ã«ã·ã¹ãã æäœãªã©ã®I/OããŠã³ããªåŠçãæ±ãçŸä»£ã®JavaScriptéçºã®åºç€ã§ããES2018ã§å°å ¥ãããéåæã€ãã¬ãŒã¿ã¯ãéåæããŒã¿ã¹ããªãŒã ãæ±ãããã®åŒ·åãªã¡ã«ããºã ãæäŸããŸãããscanããã«ããŒã¯ãRxJSã®ãããªã©ã€ãã©ãªã§ããèŠãããã¹ã¿ã³ãã¢ãã³ã®ãŠãŒãã£ãªãã£ãšããŠãå©çšå¯èœã«ãªãã€ã€ããããããã®éåæããŒã¿ã¹ããªãŒã ãåŠçãããããªãå¯èœæ§ãè§£ãæŸã¡ãŸãã
éåæã€ãã¬ãŒã¿ã®çè§£
ãscanãã«é£ã³èŸŒãåã«ãéåæã€ãã¬ãŒã¿ãäœã§ããããããããããŸããããéåæã€ãã¬ãŒã¿ã¯ãéåæã€ãã¬ãŒã¿ãããã³ã«ã«æºæ ãããªããžã§ã¯ãã§ãããã®ãããã³ã«ã¯ã2ã€ã®ããããã£ãæã€ãªããžã§ã¯ãã«è§£æ±ºããããããã¹ãè¿ã `next()` ã¡ãœãããå®çŸ©ããŸãããã®ããããã£ãšã¯ `value`ïŒã·ãŒã±ã³ã¹ã®æ¬¡ã®å€ïŒãš `done`ïŒã€ãã¬ãŒã¿ãçµäºãããã©ããã瀺ãããŒãªã¢ã³å€ïŒã§ããéåæã€ãã¬ãŒã¿ã¯ãæéãšãšãã«å°çããããŒã¿ããååŸã«éåææäœãå¿ èŠãšããããŒã¿ãæ±ãéã«ç¹ã«äŸ¿å©ã§ãã
以äžã«éåæã€ãã¬ãŒã¿ã®åºæ¬çãªäŸã瀺ããŸãïŒ
async function* generateNumbers() {
yield 1;
yield 2;
yield 3;
}
async function main() {
const iterator = generateNumbers();
let result = await iterator.next();
console.log(result); // { value: 1, done: false }
result = await iterator.next();
console.log(result); // { value: 2, done: false }
result = await iterator.next();
console.log(result); // { value: 3, done: false }
result = await iterator.next();
console.log(result); // { value: undefined, done: true }
}
main();
ãscanããã«ããŒã®ç޹ä»
ãscanããã«ããŒïŒ`accumulate`ã`reduce`ãšããŠãç¥ãããŠããŸãïŒã¯ãã¢ãã¥ã ã¬ãŒã¿é¢æ°ãåå€ã«é©çšãã环èšçµæãåºåããããšã§éåæã€ãã¬ãŒã¿ã倿ããŸããããã¯é åã® `reduce` ã¡ãœããã«äŒŒãŠããŸãããéåæã§ã€ãã¬ãŒã¿äžã§åäœããŸãã
æ¬è³ªçã«ããscanãã¯éåæã€ãã¬ãŒã¿ãã¢ãã¥ã ã¬ãŒã¿é¢æ°ããããŠãªãã·ã§ã³ã®åæå€ãåããŸãããœãŒã¹ã€ãã¬ãŒã¿ããåºåãããåå€ã«å¯ŸããŠãã¢ãã¥ã ã¬ãŒã¿é¢æ°ãåã®çޝèšå€ïŒãŸãã¯æåã®å埩ã®å Žåã¯åæå€ïŒãšã€ãã¬ãŒã¿ããã®çŸåšã®å€ã§åŒã³åºãããŸããã¢ãã¥ã ã¬ãŒã¿é¢æ°ã®çµæã次ã®çޝèšå€ãšãªãããããçµæã®éåæã€ãã¬ãŒã¿ã«ãã£ãŠåºåãããŸãã
æ§æãšãã©ã¡ãŒã¿
ãscanãã䜿çšããããã®äžè¬çãªæ§æã¯æ¬¡ã®ãšããã§ãïŒ
async function* scan(sourceIterator, accumulator, initialValue) {
let accumulatedValue = initialValue;
for await (const value of sourceIterator) {
accumulatedValue = accumulator(accumulatedValue, value);
yield accumulatedValue;
}
}
- `sourceIterator`ïŒå€æå¯Ÿè±¡ã®éåæã€ãã¬ãŒã¿ã
- `accumulator`ïŒ2ã€ã®åŒæ°ïŒåã®çޝèšå€ãšã€ãã¬ãŒã¿ããã®çŸåšã®å€ïŒãåã颿°ãæ°ãã环èšå€ãè¿ãå¿ èŠããããŸãã
- `initialValue`ïŒãªãã·ã§ã³ïŒïŒã¢ãã¥ã ã¬ãŒã¿ã®åæå€ãæäŸãããªãå ŽåããœãŒã¹ã€ãã¬ãŒã¿ã®æåã®å€ãåæå€ãšããŠäœ¿çšãããã¢ãã¥ã ã¬ãŒã¿é¢æ°ã¯2çªç®ã®å€ããåŒã³åºãããŸãã
ãŠãŒã¹ã±ãŒã¹ãšäŸ
ãscanããã«ããŒã¯éåžžã«å€çšéã§ãããéåæããŒã¿ã¹ããªãŒã ãé¢ããå¹ åºãã·ããªãªã§äœ¿çšã§ããŸãã以äžã«ããã€ãã®äŸãæããŸãïŒ
1. 环èšã®èšç®
ååŒéé¡ãåºåããéåæã€ãã¬ãŒã¿ããããšããŸãããscanãã䜿çšããŠããããã®ååŒã®çޝèšãèšç®ã§ããŸãã
async function* generateTransactions() {
yield 10;
yield 20;
yield 30;
}
async function main() {
const transactions = generateTransactions();
const runningTotals = scan(transactions, (acc, value) => acc + value, 0);
for await (const total of runningTotals) {
console.log(total); // Output: 10, 30, 60
}
}
main();
ãã®äŸã§ã¯ã`accumulator`颿°ã¯çŸåšã®ååŒéé¡ãåã®åèšã«å ç®ããã ãã§ãã`initialValue`ã0ã«ããããšã§ã环èšããŒãããå§ãŸãããšãä¿èšŒããŸãã
2. ããŒã¿ãé åã«èç©ãã
ãscanãã䜿çšããŠãéåæã€ãã¬ãŒã¿ããã®ããŒã¿ãé åã«èç©ã§ããŸããããã¯ãæéãšãšãã«ããŒã¿ãåéãããããã§åŠçããå Žåã«äŸ¿å©ã§ãã
async function* fetchData() {
yield { id: 1, name: 'Alice' };
yield { id: 2, name: 'Bob' };
yield { id: 3, name: 'Charlie' };
}
async function main() {
const dataStream = fetchData();
const accumulatedData = scan(dataStream, (acc, value) => [...acc, value], []);
for await (const data of accumulatedData) {
console.log(data); // Output: [{id: 1, name: 'Alice'}], [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}], [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}, {id: 3, name: 'Charlie'}]
}
}
main();
ããã§ã¯ã`accumulator`颿°ã¯ã¹ãã¬ããæŒç®åïŒ`...`ïŒã䜿çšããŠã以åã®ãã¹ãŠã®èŠçŽ ãšçŸåšã®å€ãå«ãæ°ããé åãäœæããŸãã`initialValue`ã¯ç©ºã®é åã§ãã
3. ã¬ãŒããªããã¿ãŒã®å®è£
ããè€éãªãŠãŒã¹ã±ãŒã¹ã¯ãã¬ãŒããªããã¿ãŒã®å®è£ ã§ãããscanãã䜿çšããŠãç¹å®ã®æéæ å ã«è¡ããããªã¯ãšã¹ãã®æ°ã远跡ããã¬ãŒãå¶éãè¶ ããå Žåã¯åŸç¶ã®ãªã¯ãšã¹ããé å»¶ãããããšãã§ããŸãã
async function* generateRequests() {
// Simulate incoming requests
yield Date.now();
await new Promise(resolve => setTimeout(resolve, 200));
yield Date.now();
await new Promise(resolve => setTimeout(resolve, 100));
yield Date.now();
}
async function main() {
const requests = generateRequests();
const rateLimitWindow = 1000; // 1 second
const maxRequestsPerWindow = 2;
async function* rateLimitedRequests(source, window, maxRequests) {
let queue = [];
for await (const requestTime of source) {
queue.push(requestTime);
queue = queue.filter(t => requestTime - t < window);
if (queue.length > maxRequests) {
const earliestRequest = queue[0];
const delay = window - (requestTime - earliestRequest);
console.log(`Rate limit exceeded. Delaying for ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
yield requestTime;
}
}
const limited = rateLimitedRequests(requests, rateLimitWindow, maxRequestsPerWindow);
for await (const requestTime of limited) {
console.log(`Request processed at ${requestTime}`);
}
}
main();
ãã®äŸã§ã¯ãå éšçã«ïŒ`rateLimitedRequests`颿°å ã§ïŒ`scan`ã䜿çšããŠãªã¯ãšã¹ãã¿ã€ã ã¹ã¿ã³ãã®ãã¥ãŒãç¶æããŸããã¬ãŒãå¶éãŠã£ã³ããŠå ã®ãªã¯ãšã¹ãæ°ã蚱容æå€§å€ãè¶ ããŠãããã©ããããã§ãã¯ããŸããè¶ ããŠããå Žåã¯ãå¿ èŠãªé å»¶ãèšç®ãããªã¯ãšã¹ããyieldããåã«äžæåæ¢ããŸãã
4. ãªã¢ã«ã¿ã€ã ããŒã¿ã¢ã°ãªã²ãŒã¿ã®æ§ç¯ïŒã°ããŒãã«ãªäŸïŒ
æ§ã ãªååŒæããã®ãªã¢ã«ã¿ã€ã æ ªäŸ¡ãéçŽããå¿ èŠãããã°ããŒãã«ãªéèã¢ããªã±ãŒã·ã§ã³ãèããŠã¿ãŸããããéåæã€ãã¬ãŒã¿ã¯ããã¥ãŒãšãŒã¯èšŒåžååŒæïŒNYSEïŒããã³ãã³èšŒåžååŒæïŒLSEïŒãæ±äº¬èšŒåžååŒæïŒTSEïŒãªã©ã®ååŒæããã®äŸ¡æ ŒæŽæ°ãã¹ããªãŒãã³ã°ã§ããŸãããscanãã䜿çšããŠããã¹ãŠã®ååŒæã«ãããç¹å®ã®æ ªåŒã®å®è¡å¹³åãŸãã¯é«å€/å®å€ãç¶æããããšãã§ããŸãã
// Simulate streaming stock prices from different exchanges
async function* generateStockPrices() {
yield { exchange: 'NYSE', symbol: 'AAPL', price: 170.50 };
yield { exchange: 'LSE', symbol: 'AAPL', price: 170.75 };
await new Promise(resolve => setTimeout(resolve, 50));
yield { exchange: 'TSE', symbol: 'AAPL', price: 170.60 };
}
async function main() {
const stockPrices = generateStockPrices();
// Use scan to calculate a running average price
const runningAverages = scan(
stockPrices,
(acc, priceUpdate) => {
const { total, count } = acc;
return { total: total + priceUpdate.price, count: count + 1 };
},
{ total: 0, count: 0 }
);
for await (const averageData of runningAverages) {
const averagePrice = averageData.total / averageData.count;
console.log(`Running average price: ${averagePrice.toFixed(2)}`);
}
}
main();
ãã®äŸã§ã¯ã`accumulator`颿°ã¯äŸ¡æ Œã®çޝèšãšåä¿¡ããæŽæ°ã®æ°ãèšç®ããŸããæçµçãªå¹³åäŸ¡æ Œã¯ããããã®çޝèšå€ããèšç®ãããŸããããã«ãããç°ãªãã°ããŒãã«åžå Žã«ãããæ ªäŸ¡ã®ãªã¢ã«ã¿ã€ã ãã¥ãŒãæäŸãããŸãã
5. ãŠã§ããµã€ãã®ãã©ãã£ãã¯ãã°ããŒãã«ã«åæãã
äžçäžã«èšçœ®ããããµãŒããŒãããŠã§ããµã€ãã®èšªåããŒã¿ã¹ããªãŒã ãåä¿¡ããã°ããŒãã«ãªãŠã§ãåæãã©ãããã©ãŒã ãæ³åããŠã¿ãŠãã ãããåããŒã¿ãã€ã³ãã¯ããŠã§ããµã€ãã蚪ãããŠãŒã¶ãŒã衚ããŸãããscanãã䜿çšããããšã§ãåœããšã®ããŒãžãã¥ãŒã®ãã¬ã³ãããªã¢ã«ã¿ã€ã ã§åæã§ããŸããããŒã¿ã`{ country: "US", page: "homepage", timestamp: 1678886400 }`ã®ãããªåœ¢åŒã§ãããšããŸãã
async function* generateWebsiteVisits() {
yield { country: 'US', page: 'homepage', timestamp: Date.now() };
yield { country: 'CA', page: 'product', timestamp: Date.now() };
yield { country: 'UK', page: 'blog', timestamp: Date.now() };
yield { country: 'US', page: 'product', timestamp: Date.now() };
}
async function main() {
const visitStream = generateWebsiteVisits();
const pageViewCounts = scan(
visitStream,
(acc, visit) => {
const { country } = visit;
const newAcc = { ...acc };
newAcc[country] = (newAcc[country] || 0) + 1;
return newAcc;
},
{}
);
for await (const counts of pageViewCounts) {
console.log('Page view counts by country:', counts);
}
}
main();
ããã§ã¯ã`accumulator`颿°ã¯ååœããšã®ã«ãŠã³ã¿ãŒãæŽæ°ããŸããåºåã¯ãæ°ãã蚪åããŒã¿ãå°çãããã³ã«ãååœããšã®çޝèšããŒãžãã¥ãŒæ°ã瀺ããŸãã
ãscanãã䜿çšããå©ç¹
ãscanããã«ããŒã¯ãéåæããŒã¿ã¹ããªãŒã ãæ±ãéã«ããã€ãã®å©ç¹ãæäŸããŸãïŒ
- 宣èšçãªã¹ã¿ã€ã«ïŒ ãscanãã䜿çšãããšã环èšåŠçããžãã¯ã宣èšçãã€ç°¡æœã«è¡šçŸã§ããã³ãŒãã®å¯èªæ§ãšä¿å®æ§ãåäžããŸãã
- éåæåŠçïŒ ã¢ãã¥ã ã¬ãŒã¿é¢æ°å ã®éåææäœãã·ãŒã ã¬ã¹ã«åŠçãããããI/OããŠã³ããªã¿ã¹ã¯ãå«ãè€éãªã·ããªãªã«é©ããŠããŸãã
- ãªã¢ã«ã¿ã€ã åŠçïŒ ãscanãã¯ããŒã¿ã¹ããªãŒã ã®ãªã¢ã«ã¿ã€ã åŠçãå¯èœã«ãã倿Žãçºçãããšãã«ããã«åå¿ããããšãã§ããŸãã
- æ§æå¯èœæ§ïŒ ä»ã®éåæã€ãã¬ãŒã¿ãã«ããŒãšç°¡åã«çµã¿åãããããšã§ãè€éãªããŒã¿åŠçãã€ãã©ã€ã³ãäœæã§ããŸãã
ãscanãã®å®è£ ïŒå©çšã§ããªãå ŽåïŒ
äžéšã®ã©ã€ãã©ãªã¯çµã¿èŸŒã¿ã®ãscanããã«ããŒãæäŸããŠããŸãããå¿ èŠã§ããã°ç°¡åã«ç¬èªã«å®è£ ã§ããŸãã以äžã«ç°¡åãªå®è£ ã瀺ããŸãïŒ
async function* scan(sourceIterator, accumulator, initialValue) {
let accumulatedValue = initialValue;
let first = true;
for await (const value of sourceIterator) {
if (first && initialValue === undefined) {
accumulatedValue = value;
first = false;
} else {
accumulatedValue = accumulator(accumulatedValue, value);
}
yield accumulatedValue;
}
}
ãã®å®è£ ã¯ããœãŒã¹ã€ãã¬ãŒã¿ãå埩åŠçããåå€ã«ã¢ãã¥ã ã¬ãŒã¿é¢æ°ãé©çšããŠã环èšçµæãyieldããŸãã`initialValue`ãæäŸãããªãå Žåã«ããœãŒã¹ã€ãã¬ãŒã¿ã®æåã®å€ãåæå€ãšããŠäœ¿çšããã±ãŒã¹ãåŠçããŸãã
`reduce`ãšã®æ¯èŒ
ãscanããš`reduce`ãåºå¥ããããšãéèŠã§ããäž¡æ¹ãšãã€ãã¬ãŒã¿äžã§åäœããã¢ãã¥ã ã¬ãŒã¿é¢æ°ã䜿çšããŸããããã®åäœãšåºåã¯ç°ãªããŸãã
- `scan`ã¯åå埩åŠçã§çޝèšå€ãåºåããèç©ã®å®è¡å±¥æŽãæäŸããŸãã
- `reduce`ã¯ãã€ãã¬ãŒã¿å ã®ãã¹ãŠã®èŠçŽ ãåŠçããåŸã«æçµçãªçޝèšå€ã®ã¿ãåºåããŸãã
ãããã£ãŠããscanãã¯èç©ã®äžéç¶æ ã远跡ããå¿ èŠãããã·ããªãªã«é©ããŠããã`reduce`ã¯æçµçµæã®ã¿ãå¿ èŠãªå Žåã«é©ããŠããŸãã
ãšã©ãŒãã³ããªã³ã°
éåæã€ãã¬ãŒã¿ãšãscanããæ±ãéã«ã¯ããšã©ãŒãé©åã«åŠçããããšãéèŠã§ãããšã©ãŒã¯ãå埩åŠçäžãŸãã¯ã¢ãã¥ã ã¬ãŒã¿é¢æ°å ã§çºçããå¯èœæ§ããããŸãã`try...catch`ãããã¯ã䜿çšããŠããããã®ãšã©ãŒããã£ããããŠåŠçã§ããŸãã
async function* generatePotentiallyFailingData() {
yield 1;
yield 2;
throw new Error('Something went wrong!');
yield 3;
}
async function main() {
const dataStream = generatePotentiallyFailingData();
try {
const accumulatedData = scan(dataStream, (acc, value) => acc + value, 0);
for await (const data of accumulatedData) {
console.log(data);
}
} catch (error) {
console.error('An error occurred:', error);
}
}
main();
ãã®äŸã§ã¯ã`try...catch`ãããã¯ã`generatePotentiallyFailingData`ã€ãã¬ãŒã¿ã«ãã£ãŠã¹ããŒããããšã©ãŒããã£ããããŸãããã®åŸããšã©ãŒããã°ã«èšé²ããããæäœãå詊è¡ãããªã©ãé©åã«ãšã©ãŒãåŠçã§ããŸãã
çµè«
ãscanããã«ããŒã¯ãJavaScriptã®éåæã€ãã¬ãŒã¿ã§éåæã®çޝèšåŠçãå®è¡ããããã®åŒ·åãªããŒã«ã§ããããã«ãããè€éãªããŒã¿å€æã宣èšçãã€ç°¡æœã«è¡šçŸããéåææäœãé©åã«åŠçããããŒã¿ã¹ããªãŒã ããªã¢ã«ã¿ã€ã ã§åŠçã§ããŸãããã®æ©èœãšãŠãŒã¹ã±ãŒã¹ãçè§£ããããšã§ããscanããæŽ»çšããŠãããå ç¢ã§å¹ççãªéåæã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã环èšã®èšç®ãé åãžã®ããŒã¿èç©ãã¬ãŒããªããã¿ãŒã®å®è£ ããªã¢ã«ã¿ã€ã ããŒã¿ã¢ã°ãªã²ãŒã¿ã®æ§ç¯ãªã©ããããã®å Žåã§ãããscanãã¯ã³ãŒããç°¡çŽ åããå šäœçãªããã©ãŒãã³ã¹ãåäžãããããšãã§ããŸããéåæããŒã¿ã¹ããªãŒã ã®åŠçäžã«äžéçãªçޝèšå€ã«ã¢ã¯ã»ã¹ããå¿ èŠãããå Žåã¯ããšã©ãŒãã³ããªã³ã°ãèæ ®ãã`reduce`ã®ä»£ããã«ãscanããéžæããããšãå¿ããªãã§ãã ãããRxJSã®ãããªã©ã€ãã©ãªãæ¢æ±ããããšã§ããªã¢ã¯ãã£ãããã°ã©ãã³ã°ãã©ãã€ã å ã§ã®ãscanãã®çè§£ãšå®è·µçãªå¿çšãããã«æ·±ããããšãã§ããŸãã