一時停止と再開機能のjavascript

JavaScriptの非同期プログラミングは、常に我々が最もコールバックを開始し、問題となっていたが、「発明」の約束はあまりにも深くネストされたコールバックの問題を解決するため、コールバック地獄をトリガーします。しかし、約束の虐待(その後のシリーズ)のために、コードが読みやすくなります。この時点で、非同期のawaitが判明、それは私たちが何人かの人々はそれが非同期プログラミングJavaScriptの特効薬であると言うので、同期して、ただ驚くばかりで非同期コードを書くことができます。

PSコードは、実証することはできません

function getProfile(id) {
  return window.fetch(`https://api.com/wedding/profile/${weddingId}`
}

async function getWeddingDetail(weddingId) {
  try {
    // 暂停执行
    const wedding = await window.fetch(`https://api.com/wedding/${weddingId}`);
    // 当结果返回恢复执行,接着继续暂停
    const groom = await getProfile(wedding.groomId);
    // ... 恢复执行 -> 暂停 ...
    const bride = await getProfile(wedding.brideId);
    // ... 恢复执行
    return { wedding, bride, groom };
  } catch (error) {
    handleError(error);
  }
}

銀の弾などありません

しかし、コンピュータサイエンスの特効薬はありません。欠点も、たとえば、あなたが信じていない、のawait書くことを忘れている非同期待ちますか?

仮定誰かが関数と呼ばれるツールを書いたgetProfileその具体的な実現を理解せずに、あなたも、同期機能、としてそれを入れていないgetProfile非同期。

もちろん、これはただの小さな問題で、この関数を呼び出すための別の呼び出し機能がある場合は、関数内で非同期を使用している場合、その関数を呼び出すことですが、非同期になるために持っている私は不快に作られました.. ....ヒイラギくそ!今、あなたのアイデアを得ます。

両方の世界の最良の方法はありますか?

// getWeddingDetail 根本不用关心内部的函数是异步or同步
function getWeddingDetail(weddingId) {
  const wedding = window.fetch(`https://api.com/wedding/${weddingId}`);
  const groom = getProfile(wedding.groomId);
  const bride = getProfile(wedding.brideId);
  return { wedding, bride, groom };
}

何も中間層は解決することはできませんされて

コア非同期プログラミング、一時停止及び再開機能が実行されます。ドライjsのジョブを実行される機能を中断または再開する決定を実行するには、我々はさらにエンジンを達成するために、今日がありますか?

いいえ!私はそれがノウハウJSエンジンを達成する方法ではありません、C ++を知りません。

しかし、その後、私はいくつかの制限があることを、当然のことながら、上記の要件を達成しようとし、中間層(機能ランタイム)を書くことができます。

入口機能

あなたは以下の機能を実行したいと仮定します。

function main() {
  const id = 123;
  console.log('Getting wedding:', id);

  const { wedding, bride, groom } = getWeddingDetail(id);

  console.log('Wedding detail:', wedding);
}

私たちは、次のように実行することができることを期待します:

function runtime(mainFn) {
  mainFn();
}

// start runtime
runtime(main);

基本的な枠組みは、そこその後、やっているのですか?

まず、ないのawait、機能の実行を中断するかの前提を見つけ出します。

次に、適切な場所で実行を再開します。

リターンとスロー:JS割り込み関数を実行するには2つの方法があります。私はそれが異常な中断が発生するの出会いを表しているので、投げることを選びました。さて、私たちはどのようなランタイムを変換します

function runtime(mainFn) {
  const _originalFetch = window.fetch;
  window.fetch = (url, options) => {
    // "暂停"
    throw new Error();
  };
  // 运行入口函数
  runMain();

  function runMain() {
    try {
      mainFn();
    } catch (error) {
      // 函数 "暂停"
      // 恢复并重新执行 mainFn
      runMain();
    }
  }
}

機能「ブレーク」これら二つの点で「復元」を見に集まって、このコードが表示され、との問題を無視し、それは明確な目的が達成されたです。それを最適化するために、次。

第一の理由はrunMain、正常に実行された後にのみwindow.fetchです。

function runtime(mainFn) {
  const _originalFetch = window.fetch
  window.fetch = (url, options) => {
    _originalFetch(url, options).then(res => {
      // 返回结果后恢复执行
      runMain()
    })
    throw new Error()
  }

  runMain();

  function runMain() {
    try {
      mainFn();
    } catch (error) {
      // ignore
    }
  }
}

mainFn無限ループの実装につながった例外がスローされるたびに、window.fetch。

この問題を解決するために、我々が唯一の最初のフェッチ例外をスローする必要がありそうという、キャッシュを導入する必要があり、その後の要求に応答を返します。

function runtime(mainFn) {
  const _originalFetch = window.fetch
  windo.fetch = (url, options) => {
    if (cache.has([url, options])) return cache.get([url, options])

    _originalFetch(url, options).then(res => {
      cache.set([url, options], res)
      runMain()
    })

    throw new Error()
  }

  runMain();

  function runMain() {
    try {
      mainFn();
    } catch (error) {
      // ignore
    }
  }
}

成功!

プログラムを実行して、繰り返し実行複数回によるコンソール出力を確認し、'Getting wedding:', 123また、それは副作用引き起こさにconsole.logで複数回、表示しました。

第二に、純粋な機能

runSideEffects():実行時にのみ、あなたのコードの副作用がある場合は、あなたが制限を追加しなければならない、純粋な関数を実行することができました。

function main() {
  const id = 123;
  runSideEffects(() => console.log('Getting wedding:', id));

  const { wedding, bride, groom } = getWeddingDetail(id);

  runSideEffects(() => console.log('Wedding detail:', wedding));
}

達成することは非常に簡単副作用:

function runtime(mainFn) {
  // 参考上面的代码

  // 提供 `runSideEffects`
  const sideEffects = [];
  window.runSideEffects = fn => {
    sideEffects.push(fn);
  };

  runMain();

  function runMain() {
    try {
      mainFn();
      sideEffects.forEach(fn => fn());
    } catch (error) {
      // 清除副作用
      sideEffects.splice(0, sideEffects.length);
    }
  }
  
}

再度実行してください'Getting wedding:', 123〜友人だけ一度に表示

最後に、いくつかの何をしましたか?

一時停止と再開の模倣機能するためには、我々は「再開」機能を再度実行して投げることにより、「一時停止」機能に間違いがあります。

一時停止からの「回復」のためには、関数の戻り値を置き換え、エラーをスローする必要があり、我々は、この目的を達成するためのキャッシュメカニズムを使用します。

最後に、リピート機能を確保するためには、それが純粋な関数に変換する必要があります。副作用がある場合、それらは関数が成功した後、その後、副作用を実行し、収集されています。

そんなに、何実用化を引き?

以下からのインスピレーションは、サスペンスに反応しますサスペンスで、それは次のようにデータを取得することができます:

function Component() {
  const data = getDataFromNetwork();
  return <div />;
}

それは非同期関数であるのでgetDataFromNetworkは、非同期要求を開始しますが、それは同期動作であるリアクトようです。それはおかしいです -

オリジナルを読む:PAUSE-と-再開-A-JavaScriptの機能

おすすめ

転載: www.cnblogs.com/fayin/p/12066559.html