Javascriptの中のasync await


async/awaitはES 7の重要な特性の一つであり、現在コミュニティで公認されている優秀な非同期解決策でもあります.現在、async/awaitという特性はすでにstage 3の提案であり、TC 39の進捗状況を見てもいいです.この文章はasync/awaitがどのように働いているかを分かち合います.本文を読む前に、Promise、generator、yieldなどのES 6に関する知識を持ってほしいです.
async/awaitを詳しく紹介する前に、現在ES 6において比較的良い非同期処理方法を振り返ってみます.以下の例では、データ要求はNode.jsのrequestモジュールを用いて、データインターフェースはGigthub v 3 api文書で提供されるrepoコード倉庫の詳細APIを例として示している.
Promiseの非同期処理
Node.jsの非同期IOは高合併への支持を得ていますが、同時に「リプライ」が災害となり、逆転地獄を引き起こしやすいです.伝統的な方法は、例えば、具体的な名前関数を使用して、入れ子の層数を減らすことができますが、コードがより明確に見えるようにします.しかし、比較的に悪い符号化とデバッグ体験をもたらします.いつもCurl+fを使って、ある具体的な名前関数の定義を探す必要があります.これはIDEウィンドウを常に上下に動かします.Promiseを使うと、入れ子の層数をよく減らすことができます.またPromiseの実現は状態マシンを採用しています.関数の中でreolveとrejectを通じて流れをコントロールすることができます.以下はPromiseを使用した例です.
const request = require('request');//    url headerconst options = {
  url: 'https://api.github.com/repos/cpselvis/zhihu-crawler',
  headers: {
    'User-Agent': 'request'
  }};//       const getRepoData = () => {
  return new Promise((resolve, reject) => {
    request(options, (err, res, body) => {
      if (err) {
        reject(err);
      }
      resolve(body);
    });
  });};getRepoData()
  .then((result) => console.log(result);)
  .catch((reason) => console.error(reason););//        Promise      ,  ://   then        promise// getRepoData()//   .then((value2) => {return promise2})//   .then((value3) => {return promise3})//   .then((x) => console.log(x))
しかし、Promiseにはまだ欠陥があります.入れ子を減らすだけで、入れ子を完全に除去することはできません.例を挙げると、複数のpromiseシリアルが実行される場合、最初のpromiseの論理が実行され終わった後、そのthen関数の中で第二のpromiseを実行する必要があります.この時、入れ子が発生します.また、Promiseを採用しているコードはまだ非同期のように見えますが、書いてあるコードが同期になったらいいですね.
Generatorの非同期処理
ゲナートについて言えば、あなたはそれをよく知らないはずです.Node.jsでは回調の処理について、私達がよく使うTJ/Coはgeneratorを使ってpromiseを結合して実現します.coはcooutineの略称です.python、luaなどの言語に配慮した協働です.それは非同期コード論理を同期方式に書くことができます.コードの読み取りと組織がより明確になり、デバッグにも便利です.
const co = require('co');const request = require('request');const options = {
  url: 'https://api.github.com/repos/cpselvis/zhihu-crawler',
  headers: {
    'User-Agent': 'request'
  }};// yield         generatorconst getRepoData = function* () {
  return new Promise((resolve, reject) => {
    request(options, (err, res, body) => {
      if (err) {
        reject(err);
      }
      resolve(body);
    });
  });};co(function* () {
  const result = yield getRepoData;
  // ...          ,      ,  
  // const r1 = yield getR1;
  // const r2 = yield getR2;
  // const r3 = yield getR3;
  //   yield     ,  yield         generator             yield  。
  return result;}).then(function (value) {
  console.log(value);}, function (err) {
  console.error(err.stack);});
async/awaitの非同期処理
coはコミュニティ内の優秀な非同期解決策ですが、言語標準ではなく、移行案です.ES 7言語レベルはasync/awaitを提供して言語レベルの難題を解決します.新しい航路のアイエルツは今async/awaitはIE edgeの中で直接使うことができましたが、chromeとNode.jsはまだサポートしていません.幸いにも、babelはすでにasyncのtransformをサポートしていますので、私達が使う時にbabelを導入すればいいです.始まる前に以下のpackageを導入したいです.preset-stage-3に私たちが必要なasync/awaitのコンパイルファイルがあります.
Browserであれ、Node.jsであれ、下のパッケージをインストールする必要があります.
$ npm install babel-core --save$ npm install babel-preset-es2015 --save$ npm install babel-preset-stage-3 --save
ここでは、Babelオフィシャルで提供されているrequire Hookを使用する方法を紹介します.requireを通して入ってきたら、次の書類をrequireする時はバベルの処理をします.CommunJsは同期モジュール依存であることを知っていますので、可能な方法です.この時、二つのファイルを作成する必要があります.一つは起動したjsファイルで、もう一つは本当にプログラムを実行するjsファイルです.
起動ファイルindex.js
require('babel-core/register');require('./async.js');
本当にプログラムを実行するasync.js
const request = require('request');const options = {
  url: 'https://api.github.com/repos/cpselvis/zhihu-crawler',
  headers: {
    'User-Agent': 'request'
  }};const getRepoData = () => {
  return new Promise((resolve, reject) => {
    request(options, (err, res, body) => {
      if (err) {
        reject(err);
      }
      resolve(body);
    });
  });};async function asyncFun() {
 try {
    const value = await getRepoData();
    // ...     yield  ,         ,      ,  
    // const r1 = await getR1();
    // const r2 = await getR2();
    // const r3 = await getR3();
    //   await     ,  await           (  generator)             await  。
    return value;
  } catch (err) {
    console.log(err);
  }}asyncFun().then(x => console.log(`x: ${x}`)).catch(err => console.error(err));
注意点:
  • asyncは中の小包の内容を説明して同期する方式で実行します.awaitは順制御を行います.毎回awaitを実行します.プログラムはawaitの戻り値を待ってから、その後のawaitを実行します.
  • awaitの後に呼び出された関数はプロミセに戻る必要があります.また、この関数はgeneratorではなく普通の関数です.
  • awaitはasync関数でしか使えません.普通の関数ではエラーが発生します.
  • awaitコマンドの後のPromiseオブジェクトは、実行結果がrejectである可能性がありますので、awaitコマンドをtry...catchコードブロックに置いた方がいいです.
  • 実は、async/awaitの使い方はcoと同じです.awaitとyieldは一時停止を表しています.外はasyncまたはcoを包んで、中のコードは同期方式で処理できます.でもasync/awaitの中のawaitの後に付いている関数は別の処理がいらないです.coはそれをgeneratorと書く必要があります.