JavaScriptでのasyncの使い方を詳しく解説

巴扎黑
リリース: 2017-08-23 14:00:15
オリジナル
3865 人が閲覧しました

この記事では、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);
  }
};
ログイン後にコピー

thunkify関数を使うのがカリー化の考え方に基づいています。 、最後に行われた入力パラメータはコールバック関数です。thunkify を使用すると、yield 関数の自動処理を簡単に実現できます。では、これら 2 つの実装方法と互換性のある方法はありますか? マスター TJ は、co ライブラリーという別のライブラリーを提供しました。まず、その使用法を見てみましょう。 co ライブラリの実装を見てください。co ライブラリはデフォルトで Promise オブジェクトを返します。yield の後の値 (上記の res.value など) は、co ライブラリによって Promise に変換されます。実装のアイデアは非常に単純で、基本的には再帰を使用します。一般的なアイデアは次のとおりです。


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);
  })();
};
ログイン後にコピー

toPromise は、いくつかの型を Promise に変換することです。ここで、どの型を yield の後に配置できるかを確認します。一般的に使用されるものを見てください:


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);
ログイン後にコピー

最近、Node は非同期操作を行うために使用できる async/await をサポートしました:

究極のソリューション


// readTwoFile的实现与上面类似,readFile既可以利用Promise也可以利用thunkify
// co库返回一个Promise对象
co(readTwoFile).then(data => console.log(data));
ログイン後にコピー

async/await の機能コードは非常に読みやすく、同期メソッドです。コールバック問題をエレガントに解決するために他の外部ライブラリ (co ライブラリなど) に依存する必要はなくなりました

以上がJavaScriptでのasyncの使い方を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!