この記事では、JavaScript の非同期の使い方を主に紹介します。編集者がそれを参考にさせていただきます。エディターをフォローして見てみましょう
前に書いています
この記事では、ファイルを順番に読み取るための最適なメソッドを実装します。その実装方法は、最も古いコールバックメソッドから現在の非同期メソッドまでです。サンク図書館と共同図書館についての私の理解。達成される効果: a.txt と b.txt を順番に読み取り、読み取った内容を文字列に連結します。
同期読み取り
const readTwoFile = () => { const f1 = fs.readFileSync('./a.txt'), f2 = fs.readFileSync('./b.txt'); return Buffer.concat([f1, f2]).toString(); };
この方法は、あまりにもネストがなく、非常にわかりやすく、よく管理されています。しかし、この方法には最大の問題があります。ノードが推奨するのは集中的な I/O を処理するための非同期 I/O であり、同期読み取りはサーバーの CPU を大幅に浪費します。この方法の欠点は明らかに利点を上回るため、そのままパスしてください。 (実際、ノード内の非同期プログラミング ソリューションの目標は、同期セマンティクスと非同期実行を実現することです。)
コールバックを使用して読み取る
const readTwoFile = () => { let str = null; fs.readFile('./a.txt', (err, data) => { if (err) throw new Error(err); str = data; fs.readFile('./b.txt', (err, data) => { if (err) throw new Error(err); str = Buffer.concat([str, data]).toString(); }); }); };
コールバックを使用すると、実装が非常に簡単です。ネストするだけです。しかし、この場合、保守が難しく、理解が難しい状況が簡単に発生する可能性があり、最も極端なケースはコールバック地獄です。
Promise の実装
const readFile = file => new Promise((reslove, reject) => { fs.readFile(file, (err, data) => { if (err) reject(err); reslove(data); }); }); const readTwoFile = () => { let bf = null; readFile('./a.txt') .then( data => { bf = data; return readFile('./b.txt'); }, err => { throw new Error(err) } ) .then( data => { console.log(Buffer.concat([bf, data]).toString()) }, err => { throw new Error(err) } ); };
Promise は水平方向の拡張コールバックを垂直方向の拡張に変換することができ、これによりいくつかの問題が解決されますが、Promise によって引き起こされる問題は、一見するとそれだけに見えますが、それはコードの冗長性です。クールではありませんが、コールバック関数のネストに比べて大幅に改善されました。
yield
ジェネレーターは本質的にはコルーチンです。コルーチン、スレッド、プロセス間の違いと接続を見てみましょう。
プロセス: における基本的なリソース割り当て。オペレーティング システム ユニット
スレッド: オペレーティング システムにおけるリソース スケジューリングの基本単位
コルーチン: スレッドより小さい実行ユニット。独自の CPU コンテキスト、1 つのコルーチンと 1 つのスタックが存在する場合があります
プロセス内 1 つのスレッド内に複数のスレッドと複数のコルーチンが存在する場合があります。プロセスとスレッドの切り替えはオペレーティング システムによって制御されますが、コルーチンの切り替えはプログラマー自身によって制御されます。非同期 I/O は、集中的な I/O を処理するためにコールバックを使用します。また、コルーチンを切り替えることで、I/O 操作をコルーチンに書き込み、次のように処理することもできます。ああ、CPU を他のコルーチンに明け渡すことができます。
js はコルーチン、つまり収量もサポートしています。 yield を使用すると、実行はこの場所で停止し、他のコードは実行を継続するという直感的な感覚が得られます。
function *readTwoFile() { const f1 = yield readFile('./a.txt'); const f2 = yield readFile('./b.txt'); return Buffer.concat([f1, f2]).toString(); }
yieldでの逐次読み込みも、readFileの実装方法が2つあります
thunkify
const thunkify = (fn, ctx) => (...items) => (done) => { ctx = ctx || null; let called = false; items.push((...args) => { if (called) return void 0; called = true; done.apply(ctx, args); }); try { fn.apply(ctx, items); } catch(err) { done(err); } };
const run = fn => { const gen = fn(); let res; (function next(err, data) { let g = gen.next(data); if (g.done) return void 0; g.value(next); })(); };
const readFile = file => new Promise((reslove, reject) => { fs.readFile(file, (err, data) => { if (err) reject(err); reslove(data); }); }); const run = fn => { const gen = fn(); let str = null; (function next(err, data) { let res = gen.next(data); if (res.done) return void 0; res.value.then( data => { next(null, data); }, err => { throw new Error(err); } ); })(); }; run(readTwoFile);
// readTwoFile的实现与上面类似,readFile既可以利用Promise也可以利用thunkify // co库返回一个Promise对象 co(readTwoFile).then(data => console.log(data));
以上がJavaScriptでのasyncの使い方を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。