JavaScript ã®ãªã½ã¼ã¹ç®¡ç
ãã®ã¬ã¤ãã§ã¯ãJavaScript ã§ãªã½ã¼ã¹ç®¡çãè¡ãæ¹æ³ã«ã¤ãã¦èª¬æãã¾ãããªã½ã¼ã¹ç®¡çã¯ãããé«åº¦ãªãããã¯ã§ãããé常㯠JavaScript ã«ãã£ã¦èªåçã«å¦çãããã¡ã¢ãªã¼ç®¡çã¨ã¾ã£ããåãã§ã¯ ããã¾ããããªã½ã¼ã¹ç®¡çã¨ã¯ãJavaScript ã«ãã£ã¦èªåçã«ã¯ã¯ãªã¼ã³ã¢ãããããªããªã½ã¼ã¹ã管çãããã¨ã§ããã¢ããªã±ã¼ã·ã§ã³ã®ãã¸ãã¯ã«æ¯éãããããªãéããã¡ã¢ãªã¼ã«æªä½¿ç¨ã®ãªãã¸ã§ã¯ããä¿æãã¦ãã¦ãåé¡ãªãå ´åãããã¾ããããªã½ã¼ã¹ãªã¼ã¯ã¯å¤ãã®å ´åãåä½ä¸è¯ãã¡ã¢ãªã¼ä½¿ç¨éã®éå°ãªå¢å ã«ã¤ãªããã¾ãããããã£ã¦ãããã¯åãªãæé©åã®ããã®ãªãã·ã§ã³æ©è½ã§ã¯ãªããæ£ããããã°ã©ã ãæ¸ãããã®æ ¸å¿çãªæ©è½ãªã®ã§ãã
ã¡ã¢:
ã¡ã¢ãªã¼ç®¡çã¨ãªã½ã¼ã¹ç®¡çã¯å¥åã®ãããã¯ã§ãããæçµææ®µã¨ãã¦ãã¡ã¢ãªã¼ç®¡çã·ã¹ãã ãå©ç¨ãã¦ãªã½ã¼ã¹ç®¡çããã®ãæé©ã§ããä¾ãã°ãå¤é¨ãªã½ã¼ã¹ã®ãã³ãã«ã表ã JavaScript ãªãã¸ã§ã¯ããããå ´åããã®ãã³ãã«ãã¬ãã¼ã¸ã³ã¬ã¯ã·ã§ã³ãããéã«ãªã½ã¼ã¹ãã¯ãªã¼ã³ã¢ããããããã« FinalizationRegistry ã使ãããã¨ãã§ãã¾ãããªããªãããã®å¾ãã®ãªã½ã¼ã¹ã«ã¢ã¯ã»ã¹ããææ®µã¯ç¢ºå®ã«åå¨ããªããªãããã§ãããã ãããã¡ã¤ãã©ã¤ã¶ã¼ã確å®ã«å®è¡ãããã¨ã¯éããªããããéè¦ãªãªã½ã¼ã¹ã«ã¤ãã¦ã¯ããã«ä¾åããã®ã¯å¾çã§ã¯ããã¾ããã
åé¡
ã¾ãã管çããå¿ è¦ããããªã½ã¼ã¹ã®ä¾ãããã¤ãè¦ã¦ããã¾ãããã
-
ãã¡ã¤ã«ãã³ãã«: ãã¡ã¤ã«ãã³ãã«ã¯ããã¡ã¤ã«å ã®ãã¤ãåãèªã¿æ¸ãããããã«ä½¿ç¨ããã¾ãã使ãçµãã£ããã
fileHandle.close()ãå¼ã³åºãå¿ è¦ãããã¾ããããããªãã¨ãJS ãªãã¸ã§ã¯ãã«ã¢ã¯ã»ã¹ã§ããªããªã£ãå¾ããã¡ã¤ã«ãéããã¾ã¾ã«ãªã£ã¦ãã¾ãã¾ãããªã³ã¯å ã® Node.js ããã¥ã¡ã³ãã«ã次ã®ããã«è¨è¼ããã¦ãã¾ãã<FileHandle>ãfileHandle.close()ã¡ã½ããã§éããªãã£ãå ´åããã¡ã¤ã«è¨è¿°åã¯èªåçã«éãããããã¨ãããããããã»ã¹è¦åãåºåããã¾ããããã«ãããã¡ã¢ãªã¼ãªã¼ã¯ã®é²æ¢ã«å½¹ç«ã¡ã¾ãããã ãããã®åä½ã¯ä¿¡é ¼æ§ãä½ãããã¡ã¤ã«ãéããããªãå¯è½æ§ãããããããã®åä½ã«ä¾åããªãã§ãã ããã代ããã«ã常ã«<FileHandle>ãæç¤ºçã«éãã¦ãã ãããNode.js ã§ã¯ãå°æ¥ãã®åä½ã夿´ãããå¯è½æ§ãããã¾ãã -
ãããã¯ã¼ã¯æ¥ç¶ï¼
WebSocketãRTCPeerConnectionãªã©ã®ä¸é¨ã®ã³ãã¯ã·ã§ã³ã§ã¯ãã¡ãã»ã¼ã¸ãéä¿¡ãããªãå ´åãéããªããã°ãªããªãå ´åãããã¾ããããããªãã¨æ¥ç¶ãéããã¾ã¾ã«ãªããæ¥ç¶ãã¼ã«ã®ãµã¤ãºã¯ã¨ã¦ãå¶éããã¦ããããã§ãã -
ã¹ããªã¼ã ãªã¼ãã¼:
ReadableStreamDefaultReader.releaseLock()ãå¼ã³åºããªãã£ãå ´åãã¹ããªã¼ã ã¯ããã¯ãããä»ã®ãªã¼ãã¼ãæ¶è²»ãããã¨ãã§ããªããªãã¾ãã
èªã¿åãå¯è½ãªã¹ããªã¼ã ã使ç¨ããå ·ä½çãªä¾ãæãã¾ãã
const stream = new ReadableStream({
start(controller) {
controller.enqueue("a");
controller.enqueue("b");
controller.enqueue("c");
controller.close();
},
});
async function readUntil(stream, text) {
const reader = stream.getReader();
let chunk = await reader.read();
while (!chunk.done && chunk.value !== text) {
console.log(chunk);
chunk = await reader.read();
}
// ããã§ããã¯ãè§£é¤ãå¿ãã
}
readUntil(stream, "b").then(() => {
const anotherReader = stream.getReader();
// TypeError: ReadableStreamDefaultReader constructor can only
// accept readable streams that are not yet locked to a reader
});
ããã§ã¯ã3 ã¤ã®ãã¼ã¿ãã£ã³ã¯ãåºåããã¹ããªã¼ã ãããã¾ããæå "b" ãæ¢ãã¾ã§ããã®ã¹ããªã¼ã ããèªã¿è¾¼ã¿ãè¡ãã¾ããreadUntil ããæ»ã£ãæç¹ã§ãã¹ããªã¼ã ã¯é¨åçã«ããæ¶è²»ããã¦ããªããããå¥ã®ãªã¼ãã¼ã使ç¨ãã¦èªã¿è¾¼ã¿ãç¶ãããã¨ãã§ããã¯ãã§ããããããããã¯ã®è§£æ¾ãå¿ãã¦ãã¾ã£ããããreader ã¯å©ç¨ã§ããªããªãã¾ãããããããã¹ããªã¼ã ã¯ããã¯ãããã¾ã¾ã§ãããå¥ã®ãªã¼ãã¼ã使ãããã¨ãã§ãã¾ããã
ãã®å ´åã®è§£æ±ºçã¯åç´æå¿«ã§ããreadUntilã®æå¾ã«reader.releaseLock()ãå¼ã³åºãã°ããã®ã§ããããããã¾ã ããã¤ãã®èª²é¡ãæ®ã£ã¦ãã¾ãã
-
ä¸è²«æ§ããªããã¨: ãªã½ã¼ã¹ãã¨ã«è§£æ¾æ¹æ³ãç°ãªãã¾ããä¾ãã°ã
close()ãreleaseLock()ãdisconnect()ãªã©ãããã¾ãããã®ãã¿ã¼ã³ã¯ä¸è¬åã§ãã¾ããã -
ã¨ã©ã¼å¦ç:
reader.read()ã®å¼ã³åºãã失æããå ´åã¯ã©ããªãã§ããããï¼ãã®å ´åãreadUntilã¯çµäºãã¦ãã¾ããreader.releaseLock()ã®å¼ã³åºãã«ã¯æ±ºãã¦å°éãã¾ãããããã¯try...finallyã使ã£ã¦å¯¾å¦ã§ãã¾ããjsasync function readUntil(stream, text) { const reader = stream.getReader(); try { let chunk = await reader.read(); while (!chunk.done && chunk.value !== text) { console.log(chunk); chunk = await reader.read(); } } finally { reader.releaseLock(); } }ãã ããéè¦ãªãªã½ã¼ã¹ãå ¬éãããã³ã«ããã®ä½æ¥ãè¡ãå¿ è¦ããããã¨ãè¦ãã¦ããå¿ è¦ãããã¾ãã
-
ã¹ã³ã¼ãã«ã¤ãã¦: ä¸è¨ã®ä¾ã§ã¯ã
readerã¯try...finallyæãçµäºããæç¹ã§ãã§ã«éãããã¦ãã¾ããããã®ã¹ã³ã¼ãå ã§ã¯å¼ãç¶ãå©ç¨ã§ãã¾ããã¤ã¾ããéããããå¾ã«èª¤ã£ã¦ä½¿ç¨ãã¦ãã¾ããã¨ãããã¾ãã -
è¤æ°ã®ãªã½ã¼ã¹: ç°ãªãã¹ããªã¼ã ä¸ã« 2 ã¤ã®ãªã¼ãã¼ãæã¤å ´åã両æ¹ãè§£æ¾ãããã¨ãå¿ããªãããã«ããªããã°ãªãã¾ãããããã¯ããã®ããã®è©¦ã¿ã§ãã
jsconst reader1 = stream1.getReader(); const reader2 = stream2.getReader(); try { // reader1 㨠reader2 ã§ä½ããè¡ã } finally { reader1.releaseLock(); reader2.releaseLock(); }ãããããã®ãã¨ã«ãã£ã¦ã¨ã©ã¼å¦çã®è¤éããå¢ãã¾ãããã
stream2.getReader()ã§ä¾å¤ãçºçããå ´åãreader1ã¯è§£æ¾ããã¾ãããã¾ããreader1.releaseLock()ã§ä¾å¤ãçºçããå ´åãreader2ã¯è§£æ¾ããã¾ãããã¤ã¾ããå®éã«ã¯ããããã®ãªã½ã¼ã¹ã®åå¾ã¨è§£æ¾ã®ãã¢ããããããç¬èªã®try...finallyãããã¯ã§å²ãå¿ è¦ãããã¾ããjsconst reader1 = stream1.getReader(); try { const reader2 = stream2.getReader(); try { // reader1 㨠reader2 ã§ä½ããè¡ã } finally { reader2.releaseLock(); } } finally { reader1.releaseLock(); }
releaseLock ãå¼ã³åºãã¨ãããä¸è¦åç´ãªä½æ¥ããããã«è¤éã«çµ¡ã¿åã£ãå
¥ãåç¶ã®å®åã³ã¼ãã«ã¤ãªãã£ã¦ãã¾ããã¨ããåããããã ããã§ããããã ãããããJavaScript ã§ã¯ãªã½ã¼ã¹ç®¡çã®ããã®è¨èªã¬ãã«ã§ã®ãµãã¼ããæä¾ããã¦ããã®ã§ãã
using 宣è¨ã¨ await using 宣è¨
ç¨æããã¦ãã解決çã¯ã2種é¡ã®ç¹å¥ãªå¤æ°å®£è¨ãusing 㨠await using ã§ããããã㯠const ã«ä¼¼ã¦ãã¾ããããªã½ã¼ã¹ãç ´æ£å¯è½ã§ããå ´åã夿°ã¹ã³ã¼ãå¤ã«åºãéã«èªåçã«ãªã½ã¼ã¹ãè§£æ¾ãã¾ããåè¿°ã®ä¾ãç¨ãã¦ã次ã®ããã«æ¸ãæãããã¨ãã§ãã¾ãã
{
using reader1 = stream1.getReader();
using reader2 = stream2.getReader();
// reader1 㨠reader2 ã§ä½ããè¡ã
// ãããã¯ãçµäºããåã«ãreader1 㨠reader2 ã¯èªåçã«è§£æ¾ããã
}
ã¡ã¢:
ãã®è¨äºã®å·çæç¹ã§ã¯ãReadableStreamDefaultReader ã¯ç ´æ£å¯è½ãããã³ã«ãå®è£
ãã¦ãã¾ãããããã¯ããã¾ã§ä»®å®ã®ä¾ã§ãã
ã¾ããã³ã¼ããå²ã追å ã®æ³¢æ¬å¼§ã«æ³¨ç®ãã¦ãã ãããããã«ãããusing 宣è¨ã®ããã®æ°ãã ãããã¯ã¹ã³ã¼ã ã使ããã¾ããusing ã§å®£è¨ããããªã½ã¼ã¹ã¯ãusing ã®ã¹ã³ã¼ãå¤ã«åºãã¨ãã«èªåçã«è§£æ¾ããã¾ãããã®å ´åãã¹ã³ã¼ãå¤ã«åºãã¿ã¤ãã³ã°ã¯ããã¹ã¦ã®æãå®è¡ãããã¨ãããããã¯ã©ããã§ã¨ã©ã¼ã return/break/continue ã«ééããã¨ããªã©ããããã¯ãçµäºããã¨ãã§ãã
ã¤ã¾ããusing ã¯æç¢ºãªæå¹æéãæã¤ã¹ã³ã¼ãå
ã§ã®ã¿ä½¿ç¨ã§ãã¾ããããªãã¡ãã¹ã¯ãªããã®æä¸ä½ã§ã¯ä½¿ç¨ã§ãã¾ããããªããªããã¹ã¯ãªããã®æä¸ä½ã«ãã夿°ã¯ããã®ãã¼ã¸ä¸ã®ä»å¾ã®ãã¹ã¦ã®ã¹ã¯ãªããã«ããã¦ã¹ã³ã¼ãå
ã«ããããããã¼ã¸ãã¢ã³ãã¼ããããªãéããå®è³ªçã«ãã®ãªã½ã¼ã¹ã¯è§£æ¾ãããªããã¨ã«ãªãããã§ãããã ããã¢ã¸ã¥ã¼ã«ã®æä¸ä½ã§ã¯ä½¿ç¨å¯è½ã§ããã¢ã¸ã¥ã¼ã«ã®ã¹ã³ã¼ãã¯ãã¢ã¸ã¥ã¼ã«ã®å®è¡ãå®äºããã¨çµäºããããã§ãã
ããã§ãusing ããã¤ã¯ãªã¼ã³ã¢ãããè¡ããããããã¾ãããã§ã¯ãã©ã®ããã«è¡ãããã®ã§ãããããusing ã使ç¨ããã«ã¯ããªã½ã¼ã¹ãç ´æ£å¯è½ãããã³ã«ãå®è£
ãã¦ããè¦æ±ããã¾ãããªãã¸ã§ã¯ãã [Symbol.dispose]() ã¡ã½ãããä¿æãã¦ããå ´åããã®ãªãã¸ã§ã¯ãã¯ç ´æ£å¯è½ã§ãããã®ã¡ã½ããã¯å¼æ°ãªãã§å¼ã³åºãããã¯ãªã¼ã³ã¢ãããå®è¡ãã¾ããä¾ãã°ããªã¼ãã¼ã®å ´åã[Symbol.dispose] ããããã£ã¯ releaseLock ã®åç´ãªå¥åãã©ããã¼ã«ãããã¨ãã§ãã¾ãã
// ãã¢ç¨
class MyReader {
// ã©ããã¼
[Symbol.dispose]() {
this.releaseLock();
}
releaseLock() {
// ãªã½ã¼ã¹ãéæ¾ãããã¸ãã¯
}
}
// ã¾ãã¯å¥åã使ç¨ãã¦
MyReader.prototype[Symbol.dispose] = MyReader.prototype.releaseLock;
ãã®ç ´æ£ãããã³ã«ã«ãããusing ã¯ããªã½ã¼ã¹ã®ç¨®é¡ãææ¡ãããã¨ãªãããã¹ã¦ã®ãªã½ã¼ã¹ãä¸è²«ããæ¹æ³ã§ç ´æ£ãããã¨ãã§ãã¾ãã
åã¹ã³ã¼ãã«ã¯ã宣è¨ãããé åºã§é¢é£ä»ãããããªã½ã¼ã¹ã®ãªã¹ããããã¾ããã¹ã³ã¼ããçµäºããã¨ããªã½ã¼ã¹ã¯ [Symbol.dispose]() ã¡ã½ãããå¼ã³åºããã¨ã§ãéé ã§ç ´æ£ããã¾ããä¾ãã°ãä¸è¨ã®ä¾ã§ã¯ãreader1 ã reader2 ãããåã«å®£è¨ããã¦ãããããreader2 ãã¾ãç ´æ£ãããæ¬¡ã« reader1 ãç ´æ£ããã¾ãããããªã½ã¼ã¹ã®ç ´æ£ã試ã¿ãéã«çºçããã¨ã©ã¼ã¯ãä»ã®ãªã½ã¼ã¹ã®ç ´æ£ã妨ãããã¨ã¯ããã¾ããããã㯠try...finally ãã¿ã¼ã³ã¨æ´åãã¦ããããªã½ã¼ã¹éã®ä¾åé¢ä¿ãèæ
®ããè¨è¨ã¨ãªã£ã¦ãã¾ãã
await using 㯠using ã¨ããä¼¼ã¦ãã¾ãããã®æ§æã¯ãawait ãã©ããã§ç¾ãããã¨ãæç¤ºãã¦ãã¾ããã¤ã¾ãããªã½ã¼ã¹ã宣è¨ãããã¨ãã§ã¯ãªããå®éã«ç ´æ£ãããéã«ç¾ããã¨ãããã¨ã§ããawait using ã使ç¨ããã«ã¯ããªã½ã¼ã¹ãéåæã«ç ´æ£å¯è½ã§ããå¿
è¦ãããã¾ããã¤ã¾ãã[Symbol.asyncDisposable]() ã¡ã½ãããæã£ã¦ããå¿
è¦ãããã¾ãããã®ã¡ã½ããã¯å¼æ°ãªãã§å¼ã³åºãããã¯ãªã¼ã³ã¢ãããå®äºããã¨ãã«ãããã¹ãè¿ãã¾ããããã¯ãfileHandle.close() ã®ããã«ã¯ãªã¼ã³ã¢ãããéåæã§ããå ´åã«æçã§ãããã®å ´åãç ´æ£ã®çµæã¯éåæã«ãã確èªã§ãã¾ããã
{
await using fileHandle = open("file.txt", "w");
await fileHandle.write("Hello");
// fileHandle.close() ãå®è¡ããå¾
æ©ããã
}
await using 㯠await ã®å®è¡ãè¦æ±ããããããawait ã許å¯ããã¦ããã³ã³ããã¹ãã§ã®ã¿ä½¿ç¨ã§ãã¾ããããã«ã¯ãasync 颿°å
ããã¢ã¸ã¥ã¼ã«å
ã®æä¸ä½ã§ã® await ãå«ã¾ãã¾ãã
ãªã½ã¼ã¹ã®ã¯ãªã¼ã³ã¢ããã¯ä¸¦è¡ãã¦è¡ãããã®ã§ã¯ãªããé æ¬¡è¡ããã¾ããã¤ã¾ãããããªã½ã¼ã¹ã® [Symbol.asyncDispose]() ã¡ã½ããã®è¿å¤ã await ãããã¾ã§ã次ã®ãªã½ã¼ã¹ã® [Symbol.asyncDispose]() ã¡ã½ããã¯å¼ã³åºããã¾ããã
注æç¹ï¼
usingããã³await usingã¯ãªããã¤ã³ã§ãããªã½ã¼ã¹ãletãconstãvarã使ç¨ãã¦å®£è¨ããå ´åãä»ã®ç ´æ£ãããªãå¤ã¨åæ§ã«ãèªåçãªç ´æ£ã¯è¡ããã¾ãããusingããã³await usingã使ç¨ããã«ã¯ããªã½ã¼ã¹ãç ´æ£å¯è½ï¼ã¾ãã¯éåæç ´æ£å¯è½ï¼ã§ããå¿ è¦ãããã¾ãããªã½ã¼ã¹ããããã[Symbol.dispose]()ã¾ãã¯[Symbol.asyncDispose]()ã¡ã½ãããæããªãå ´åããã®å®£è¨è¡ã§TypeErrorãçºçãã¾ãããã ãããªã½ã¼ã¹ã¯nullã¾ãã¯undefinedã§ãã£ã¦ãæ§ããªããããæ¡ä»¶ã«å¿ãã¦ãªã½ã¼ã¹ãåå¾ãããã¨ãã§ãã¾ããconstã¨åæ§ã«ãusingã¨await usingã®å¤æ°ã«ã¯åä»£å ¥ã¯ã§ãã¾ããããããããä¿æãããªãã¸ã§ã¯ãã®ããããã£ã夿´ãããã¨ã¯å¯è½ã§ãããã ãã[Symbol.dispose]()/[Symbol.asyncDispose]()ã¡ã½ããã¯å®£è¨æã«ãã§ã«ä¿åãããããã宣è¨å¾ã«ã¡ã½ããã夿´ãã¦ãã¯ãªã¼ã³ã¢ããã«ã¯å½±é¿ãã¾ããã- ã¹ã³ã¼ãã¨ãªã½ã¼ã¹ã®ã©ã¤ãã¿ã¤ã ãæ··åããéã«ã¯ãããã¤ã注æç¹ãããã¾ããä¾ã«ã¤ãã¦ã¯ã
usingãåç §ãã¦ãã ããã
DisposableStack ãªãã¸ã§ã¯ã㨠AsyncDisposableStack ãªãã¸ã§ã¯ã
using 㨠await using ã¯ç¹å¥ãªæ§æã§ããæ§æã¯ä¾¿å©ã§ãè¤éãã®å¤ããé ãã¦ããã¾ãããæã«ã¯æåã§è¡ãå¿
è¦ãããå ´åãããã¾ãã
ä¾ãã°ããªã½ã¼ã¹ããã®ã¹ã³ã¼ãã®çµäºæã«ç ´æ£ããã®ã§ã¯ãªããããããå¾ã®ã¹ã³ã¼ãã§ç ´æ£ãããå ´åã¯ã©ãã§ãããããæ¬¡ã®ãããªã±ã¼ã¹ãèãã¦ã¿ã¦ãã ããã
let reader;
if (someCondition) {
reader = stream.getReader();
} else {
reader = stream.getReader({ mode: "byob" });
}
åè¿°ã®éããusing 㯠const ã¨åæ§ã«ãåæåããå¿
è¦ããããå代å
¥ãããã¨ã¯ã§ããªãã®ã§ã次ã®ããã«æ¸ããã¨ããããããã¾ããã
if (someCondition) {
using reader = stream.getReader();
} else {
using reader = stream.getReader({ mode: "byob" });
}
ããããããã§ã¯ãã¹ã¦ã®ãã¸ãã¯ã if ã else ã®å
é¨ã«è¨è¿°ããªããã°ãªãããã³ã¼ãã®éè¤ãçºçãã¦ãã¾ãã¾ããç§ãã¡ãå®ç¾ãããã®ã¯ãããã¹ã³ã¼ãã§ãªã½ã¼ã¹ãåå¾ã»ç»é²ããå¥ã®ã¹ã³ã¼ãã§ç ´æ£ãããã¨ã§ãããã®ããã«ã¯ DisposableStack ã使ç¨ãããã¨ãã§ãã¾ããããã¯ãç ´æ£å¯è½ãªãªã½ã¼ã¹ã®éåãä¿æããããèªä½ãç ´æ£å¯è½ãªãªãã¸ã§ã¯ãã§ãã
{
using disposer = new DisposableStack();
let reader;
if (someCondition) {
reader = disposer.use(stream.getReader());
} else {
reader = disposer.use(stream.getReader({ mode: "byob" }));
}
// ãªã¼ãã¼ã§ä½ããè¡ã
// ã¹ã³ã¼ãããè±åºããåããã£ã¹ãã¼ã¶ã¼ãç ´æ£ãããã¨ããªã¼ãã¼ãç ´æ£ãã
}
ã¾ã ç ´æ£å¯è½ãããã³ã«ãå®è£
ãã¦ããªããªã½ã¼ã¹ãããå ´åãusing ã¯ãããåãä»ãã¾ããããã®å ´åã¯ãadopt() ã使ç¨ãããã¨ãã§ãã¾ãã
{
using disposer = new DisposableStack();
// ãªã¼ãã¼ã« [Symbol.dispose]() ã¡ã½ããããªãã¨ããã
// ãããã㨠using ã§ã¯ä½¿ç¨ã§ããªããªãã
// ããããæåã§ãã£ã¹ãã¼ã¶ã¼é¢æ°ã disposer.adopt ã«æ¸¡ããã¨ãã§ãã
const reader = disposer.adopt(stream.getReader(), (reader) =>
reader.releaseLock(),
);
// ãªã¼ãã¼ã§ä½ããè¡ã
// ã¹ã³ã¼ãããè±åºããåããã£ã¹ãã¼ã¶ã¼ãç ´æ£ãããã¨ããªã¼ãã¼ãç ´æ£ãã
}
ç¹å®ã®è³æºã«ãç´ã¥ãããã¦ãããªãããå®è¡ãã¹ãç ´æ£å¦çãè¨å®ãããå ´åãããã¾ãããã¨ãã°ãè¤æ°ã®æ¥ç¶ãåæã«éããã¦ããéã«ãããã¹ã¦ã®ãã¼ã¿ãã¼ã¹æ¥ç¶ãéãããã¾ãããã¨ããã¡ãã»ã¼ã¸ããã°ã«åºãããå ´åãªã©ãæãããã¾ãããã®ãããªå ´åãdefer() ã使ç¨ãããã¨ãã§ãã¾ãã
{
using disposer = new DisposableStack();
disposer.defer(() => console.log("ãã¹ã¦ã®ãã¼ã¿ãã¼ã¹æ¥ç¶ãéãããã¾ãã"));
const connection1 = disposer.use(openConnection());
const connection2 = disposer.use(openConnection());
// connection1 㨠connection2 ã§ä½ããè¡ã
// ã¹ã³ã¼ãããè±åºããåã«ããã£ã¹ãã¼ã¶ã¼ãç ´æ£ãããã¨ãã¾ã connection1 ã¨
// connection2 ãç ´æ£ãã¦ããã¡ãã»ã¼ã¸ããã°åºåãã
}
æ¡ä»¶ä»ãã§ã®ç ´æ£ããããå ´åãããããããã¾ãããä¾ãã°ãã¨ã©ã¼ãçºçããå ´åã«ã®ã¿ãå²ãå½ã¦ããããªã½ã¼ã¹ãç ´æ£ãããªã©ã§ãããã®å ´åã¯ãmove() ã使ç¨ãããã¨ã§ãé常ã§ããã°ç ´æ£ãããã¯ãã®ãªã½ã¼ã¹ãä¿æãããã¨ãã§ãã¾ãã
class MyResource {
#resource1;
#resource2;
#disposables;
constructor() {
using disposer = new DisposableStack();
this.#resource1 = disposer.use(getResource1());
this.#resource2 = disposer.use(getResource2());
// ããã¾ã§ãã©ãçããã¨ãããã¨ã¯ãæ§ç¯ä¸ã«ã¨ã©ã¼ã¯ãªãã£ãã¨ãããã¨ã§ããã
// ç ´æ£å¯è½ãªãã®ã `disposer` ãã `#disposables` ã¸å®å
¨ã«ç§»åå¯è½
this.#disposables = disposer.move();
// æ§ç¯ã«å¤±æããå ´åã`disposer` ã¯ä¸ã®è¡ã«å°éããåã«ç ´æ£ããã
// `#resource1` 㨠`#resource2` ãç ´æ£ããã
}
[Symbol.dispose]() {
this.#disposables.dispose(); // `#resource2` 㨠`#resource1` ãç ´æ£
}
}
AsyncDisposableStack 㯠DisposableStack ã¨ä¼¼ã¦ãã¾ãããéåæã®ç ´æ£å¯è½ãªã½ã¼ã¹ã使ç¨ããããã®ãã®ã§ãããã® use() ã¡ã½ããã¯éåæã®ç ´æ£å¯è½ãªãã¸ã§ã¯ããåãåããadopt() ã¡ã½ããã¯éåæã®ã¯ãªã¼ã³ã¢ãã颿°ãåãåããdispose() ã¡ã½ããã¯éåæã®ã³ã¼ã«ããã¯ãåãåãã¾ããã¾ãã[Symbol.asyncDispose]() ã¡ã½ãããæä¾ãã¦ãã¾ããåæãªã½ã¼ã¹ã¨éåæãªã½ã¼ã¹ãæ··å¨ãã¦ããå ´åã§ããåæãªã½ã¼ã¹ã渡ããã¨ãå¯è½ã§ãã
DisposableStack ã®ãªãã¡ã¬ã³ã¹ã«ã¯ãä»ã«ãä¾ã¨è©³ç´°ãããã¾ãã
ã¨ã©ã¼å¦ç
ãªã½ã¼ã¹ç®¡çæ©è½ã®ä¸»ãªç¨éã¯ãã¨ã©ã¼ãçºçããå ´åã§ãããªã½ã¼ã¹ã常ã«è§£æ¾ãããããã«å®ç¾ãããã¨ã§ããããã§ã¯ãããã¤ãã®è¤éãªã¨ã©ã¼å¦çã®ã·ããªãªã«ã¤ãã¦è¦ã¦ããã¾ãããã
ã¾ããusing ã使ç¨ãããã¨ã§ã¨ã©ã¼ã«å¯¾ãã¦å
ç¢ãªã以ä¸ã®ã³ã¼ãããå§ãã¾ãã
async function readUntil(stream, text) {
// `await using` ã§ã¯ãªã `using` ã使ç¨ããã®ã¯ `releaseLock` ãåæã§ãããã
using reader = stream.getReader();
let chunk = await reader.read();
while (!chunk.done && chunk.value !== text) {
console.log(chunk.toUpperCase());
chunk = await reader.read();
}
}
chunk ã null ã ã£ãã¨ä»®å®ãã¾ãããã®å ´åã!chunk.done 㯠TypeError ãçºçããã颿°ãçµäºãã¾ãã颿°ãçµäºããåã«ãstream[Symbol.dispose]() ãå¼ã³åºãããã¹ããªã¼ã ã®ããã¯ãè§£æ¾ããã¾ãã
const stream = new ReadableStream({
start(controller) {
controller.enqueue("a");
controller.enqueue(null);
controller.enqueue("b");
controller.enqueue("c");
controller.close();
},
});
readUntil(stream, "b")
.catch((e) => console.error(e)) // TypeError: chunk.toUpperCase is not a function
.then(() => {
const anotherReader = stream.getReader();
// ä»ã®ãªã¼ãã¼ã®ä½æã«æå
});
ã¤ã¾ããusing ã¯ã¨ã©ã¼ãé è½ãã¾ãããçºçããã¨ã©ã¼ã¯ãã¹ã¦éåºããã¾ããããã®ç´åã«ãªã½ã¼ã¹ã¯éãããã¾ããã§ã¯ããªã½ã¼ã¹ã®ã¯ãªã¼ã³ã¢ããå¦çèªä½ãã¨ã©ã¼ãéåºããå ´åã¯ã©ããªãã§ãããããããå°ã極端ãªä¾ãè¦ã¦ã¿ã¾ãããã
class MyReader {
[Symbol.dispose]() {
throw new Error("ããã¯ã®éæ¾ã«å¤±æ");
}
}
function doSomething() {
using reader = new MyReader();
throw new Error("èªã¿åãã«å¤±æ");
}
try {
doSomething();
} catch (e) {
console.error(e); // SuppressedError: An error was suppressed during disposal
}
doSomething() ã®å¼ã³åºãã§2ã¤ã®ã¨ã©ã¼ãçºçãã¦ãã¾ãã1 ã¤ã¯ doSomething ã®å®è¡ä¸ã«éåºãããã¨ã©ã¼ããã 1 ã¤ã¯æåã®ã¨ã©ã¼ãåå ã§ reader ã®ç ´æ£ä¸ã«éåºãããã¨ã©ã¼ã§ããããã 2 ã¤ã®ã¨ã©ã¼ã¯åæã«éåºããããããææããããã®ã¯ SuppressedError ã¨ãªãã¾ãããã㯠2 ã¤ã®ã¨ã©ã¼ãå
å
ããç¹æ®ãªã¨ã©ã¼ã§ãããerror ããããã£ã«ã¯å¾è
ã®ã¨ã©ã¼ããsuppressed ããããã£ã«ã¯åè
ã®ã¨ã©ã¼ãå«ã¾ãã¦ãã¦ãåè
ã®ã¨ã©ã¼ã¯å¾è
ã®ã¨ã©ã¼ã«ãã£ã¦ãæå¶ãããã¦ãã¾ãã
ãªã½ã¼ã¹ãè¤æ°ããããã®ä¸¡æ¹ãç ´æ£ä¸ã«ã¨ã©ã¼ãçºçããå ´åï¼ããã¯æ¥µãã¦ç¨ãªã±ã¼ã¹ã§ããã¯ãã ã§ããããããç ´æ£ã«å¤±æãããã¨èªä½ãç¨ã§ããããã§ãï¼ãããããã®å è¡ããã¨ã©ã¼ã¯å¾ç¶ã®ã¨ã©ã¼ã«ãã£ã¦æå¶ãããæå¶ãããã¨ã©ã¼ã®é£éãå½¢æããã¾ãã
class MyReader {
[Symbol.dispose]() {
throw new Error("ãªã¼ãã¼ã®ããã¯ã®éæ¾ã«å¤±æ");
}
}
class MyWriter {
[Symbol.dispose]() {
throw new Error("ã©ã¤ã¿ã¼ã®ããã¯ã®éæ¾ã«å¤±æ");
}
}
function doSomething() {
using reader = new MyReader();
using writer = new MyWriter();
throw new Error("èªã¿åãã«å¤±æ");
}
try {
doSomething();
} catch (e) {
console.error(e); // SuppressedError: An error was suppressed during disposal
console.error(e.suppressed); // SuppressedError: An error was suppressed during disposal
console.error(e.error); // Error: ãªã¼ãã¼ã®ããã¯ã®éæ¾ã«å¤±æ
console.error(e.suppressed.suppressed); // Error: èªã¿åãã«å¤±æ
console.error(e.suppressed.error); // Error: ã©ã¤ã¿ã¼ã®ããã¯ã®éæ¾ã«å¤±æ
}
readerã¯æå¾ã«è§£æ¾ãããããããã®ã¨ã©ã¼ãææ°ã®ãã®ã¨ãªããä»ã®ãã¹ã¦ã®ã¨ã©ã¼ã䏿¸ããã¾ããã¤ã¾ããe.errorã¨ãã¦ç¤ºããã¾ããwriterãå ã«è§£æ¾ãããããããã®ã¨ã©ã¼ã¯å ã®çµäºã¨ã©ã¼ãããé ãçºçãã¾ãããreaderã®ã¨ã©ã¼ããã¯æ©ãçºçãã¾ãããã®ãããe.suppressed.errorã¨ãã¦ç¤ºããã¾ãã- ãèªã¿è¾¼ã¿ã«å¤±æãã¾ãããã¨ããå
ã®ã¨ã©ã¼ã¯æãå¤ãã¨ã©ã¼ã§ããããã
e.suppressed.suppressedã¨ãã¦ç¤ºããã¾ãã
ä¾
>ãªãã¸ã§ã¯ã URL ã®èªåè§£æ¾
次ã®ä¾ã§ã¯ãBlob ã®ãªãã¸ã§ã¯ã URL ã使ãï¼å®éã®ã¢ããªã±ã¼ã·ã§ã³ã§ã¯ããã® Blob ã¯ãã¡ã¤ã«ããã§ããã¬ã¹ãã³ã¹ãªã©ããåå¾ããããã¨ã«ãªãã¾ãï¼ãBlob ããã¡ã¤ã«ã¨ãã¦ãã¦ã³ãã¼ãå¯è½ã«ãã¾ãããªã½ã¼ã¹ãªã¼ã¯ãé²ãããããªãã¸ã§ã¯ãURLãä¸è¦ã«ãªã£ãæç¹ï¼ã¤ã¾ãããã¦ã³ãã¼ããæ£å¸¸ã«å§ã¾ã£ãæç¹ï¼ã§ãURL.revokeObjectURL() ã使ç¨ãã¦ãªãã¸ã§ã¯ãURLãè§£æ¾ããªããã°ãªãã¾ãããURL èªä½ã¯åãªãæååã§ãããç ´æ£å¯è½ãããã³ã«ãå®è£
ãã¦ããªããããurl ã using ã§ç´æ¥å®£è¨ãããã¨ã¯ã§ãã¾ããããã®ãããurl ã®ãã£ã¹ãã¼ã¶ã¼ã¨ãã¦æ©è½ãã DisposableStack ã使ãã¾ãããªãã¸ã§ã¯ã URL ã¯ãlink.click() ãå®äºããããã©ããã§ã¨ã©ã¼ãçºçãããããæç¹ã§ disposer ãã¹ã³ã¼ãå¤ã«ãªãã¨ããã«ç ´æ£ããã¾ãã
const downloadButton = document.getElementById("download-button");
const exampleBlob = new Blob(["example data"]);
downloadButton.addEventListener("click", () => {
using disposer = new DisposableStack();
const link = document.createElement("a");
const url = disposer.adopt(
URL.createObjectURL(exampleBlob),
URL.revokeObjectURL,
);
link.href = url;
link.download = "example.txt";
link.click();
});
å¦çä¸ã®ãªã¯ã¨ã¹ãã®èªåãã£ã³ã»ã«
次ã®ä¾ã§ã¯ããªã½ã¼ã¹ã®ãªã¹ãã並è¡ã㦠fetch ã§èªã¿åãããã« Promise.all() ã使ç¨ãã¦ãã¾ããPromise.all() ã¯ã1 ã¤ã®ãªã¯ã¨ã¹ãã失æããã¨ç´ã¡ã«å¤±æããçµæã®ãããã¹ãæå¦ãã¾ããããããä»ã®å¾
æ©ä¸ã®ãªã¯ã¨ã¹ãã¯ãããã°ã©ã ãããã®çµæã«ã¢ã¯ã»ã¹ã§ããªããªã£ã¦ããå®è¡ããç¶ãã¾ãããããã®æ®ãã®ãªã¯ã¨ã¹ããä¸å¿
è¦ã«ãªã½ã¼ã¹ãæ¶è²»ããã®ãé¿ããã«ã¯ãPromise.all() ãæ±ºå®ããéã«ãé²è¡ä¸ã®ãªã¯ã¨ã¹ããèªåçã«ãã£ã³ã»ã«ããå¿
è¦ãããã¾ãããã£ã³ã»ã«å¦ç㯠AbortController ã使ç¨ãã¦å®è£
ãããã® signal ããã¹ã¦ã® fetch() å¼ã³åºãã«æ¸¡ãã¾ããPromise.all() ãå±¥è¡ãããå ´åã颿°ã¯é常éãæ»ããã³ã³ããã¼ã©ã¼ã¯ä¸æ¢ããã¾ãããã®æç¹ã§ã¯ãã£ã³ã»ã«ãã¹ãå¾
æ©ä¸ã®ãªã¯ã¨ã¹ããåå¨ããªããããåé¡ã¯ããã¾ããã䏿¹ãPromise.all() ãæå¦ããã颿°ãä¾å¤ãéåºããå ´åãã³ã³ããã¼ã©ã¼ã¯ä¸æ¢ããããã¹ã¦ã®å¾
æ©ä¸ã®ãªã¯ã¨ã¹ãããã£ã³ã»ã«ããã¾ãã
async function getAllData(urls) {
using disposer = new DisposableStack();
const { signal } = disposer.adopt(new AbortController(), (controller) =>
controller.abort(),
);
// ãã¹ã¦ã® URL ã並è¡ãã¦åå¾
// ããããã®ãªã¯ã¨ã¹ãã失æããå ´åãæªå®äºã®ãªã¯ã¨ã¹ãããã¹ã¦èªåçã«åãæ¶ãããå¯è½æ§ããã
const pages = await Promise.all(
urls.map((url) =>
fetch(url, { signal }).then((response) => {
if (!response.ok)
throw new Error(
`ã¬ã¹ãã³ã¹ã¨ã©ã¼: ${response.status} - ${response.statusText}`,
);
return response.text();
}),
),
);
return pages;
}
è½ã¨ãç©´
ãªã½ã¼ã¹è§£æ¾ã®æ§æã«ã¯ãã©ã®ãããªç¶æ³ã§ããªã½ã¼ã¹ã常ã«è§£æ¾ãããããå¼·åãªã¨ã©ã¼å¦çæ©è½ãæ°å¤ãåãã£ã¦ãã¾ãããããã§ãééãããè½ã¨ãç©´ãããã¾ãã
usingãawait usingã使ç¨ãå¿ãããã¨ããªã½ã¼ã¹ç®¡çã®æ§æã¯ãå¿ è¦ã ã¨åãã£ã¦ããå ´åã«ã®ã¿å½¹ç«ã¤ãã®ã§ããã使ãå¿ããã¨ãã¦ãè¦åãã¦ããããããªä»çµã¿ã¯ããã¾ãããæ®å¿µãªããããããäºåã«é²ãè¯ãæ¹æ³ã¯ããã¾ããããªããªããä½ããç ´æ£å¯è½ãªãªã½ã¼ã¹ã§ãããã¨ãç¤ºãæ§æä¸ã®æãããããªãä¸ãç ´æ£å¯è½ãªãªã½ã¼ã¹ã§ãã£ã¦ããèªåç ´æ£ãªãã§å®£è¨ãããå ´åãããããã§ãããããã課é¡ãæ¤åºããã«ã¯ãããããåãã§ãã«ã¼ã¨ãªã³ã¿ã¼ãçµã¿åãããå¿ è¦ãããã¾ããä¾ãã°ãtypescript-eslint ãªã©ã§ãï¼ãã®æ©è½ã«ã¤ãã¦ã¯ç¾å¨ãéçºãè¨ç»ããã¦ãã¾ãï¼ã- è§£æ¾å¾ã®ä½¿ç¨ãä¸è¬çã«ã
usingæ§æã¯ãªã½ã¼ã¹ãã¹ã³ã¼ãå¤ã«åºãéã«ç¢ºå®ã«è§£æ¾ãããããã«ãã¾ããããã¤ã³ãã£ã³ã°å¤æ°ã®ç¯å²ãè¶ ãã¦å¤ãç¶æããæ¹æ³ã¯æ°å¤ãããã¾ããJavaScript ã«ã¯ Rust ã®ãããªæææ¨©ã¡ã«ããºã ãæããªããããusingã使ç¨ããªãã¨ã¤ãªã¢ã¹ã宣è¨ããããã¯ãã¼ã¸ã£å ã§ãªã½ã¼ã¹ãä¿æããããããã¨ãå¯è½ã§ããusingã®åç §ã«ã¯ãããããè½ã¨ãç©´ã®ä¾ãæ°å¤ãæ²è¼ããã¦ãã¾ããç¹°ãè¿ãã«ãªãã¾ãããè¤éãªå¶å¾¡ããã¼ã®ä¸ã§ãããé©åã«æ¤åºãã確å®ãªæ¹æ³ã¯ãªããããæ³¨æãå¿ è¦ã§ãã
ãªã½ã¼ã¹ç®¡çæ©è½ã¯ä¸è½è¬ã§ã¯ããã¾ãããæåã§ç ´æ£ã¡ã½ãããå¼ã³åºãããã確å®ã«æ¹åããã¦ãã¾ããããªã½ã¼ã¹ç®¡çã«é¢ãããã¹ã¦ã®ãã°ãé²ãã»ã©è³¢ãã¯ããã¾ããã使ç¨ãããªã½ã¼ã¹ã®ä»æ§ãååã«çè§£ããæ³¨æãæãå¿ è¦ãããã¾ãã
ã¾ã¨ã
ãªã½ã¼ã¹ç®¡çã·ã¹ãã ã®ä¸»è¦ãªæåã¯ä»¥ä¸ã®éãã§ãã
usingããã³await using宣è¨ã¯ãèªåçã«ãªã½ã¼ã¹ãç ´æ£ãã¾ãã- ç ´æ£å¯è½ãããã³ã«ã¨éåæç ´æ£å¯è½ãããã³ã«ããªã½ã¼ã¹ãå®è£
ããããã«ã¯ããããã
Symbol.disposeããã³Symbol.asyncDisposeã使ç¨ãã¾ãã DisposableStackãªãã¸ã§ã¯ãã¨AsyncDisposableStackãªãã¸ã§ã¯ããusingããã³await usingãé©åããªãå ´åã«ä½¿ç¨ãã¾ãã
ãããã® API ãé©åã«ä½¿ç¨ããã°ãå¤ãã®å®åã³ã¼ããè¨è¿°ãããã¨ãªããããããã¨ã©ã¼ç¶æ³ã«å¯¾ãã¦ãå ç¢ã§ä¿¡é ¼æ§ã®é«ããå¤é¨ãªã½ã¼ã¹ã¨å¯¾è©±ããã·ã¹ãã ãçæã§ãã¾ãã