web-dev-qa-db-ja.com

分度器が待機している非同期タスクを追跡する方法は?

私は中規模のAngularアプリケーションを使用しており、いくつかの理由により、私の本番環境に対して実行すると、いくつかの分度器テストがタイムアウトします。

分度器が非同期タスクを待機しているため、タイムアウトが発生することはほぼ間違いありません。私はゾーンについて知っており、ngZoneから長時間実行されている非同期タスクをすべて保持しようとしました( FAQ に従って)が、何らかの理由で分度器はまだタイムアウトしています。

何かを見逃した可能性がありますが、問題のデバッグ方法がわかりません。 コード分度器のどの部分が待機しているかを確認する方法はありますか?

NgZoneは、実行中のマイクロタスクまたはマクロタスクがあるかどうかを判別するための関数のみを公開しますが、どちらがどれであるかはわかりません。

EDIT:分度器が示すようなタイムアウトエラーの典型的な例:

失敗:非同期の待機中にタイムアウトしましたAngularタスクが11秒後に完了するのを待っています。これは、現在のページがAngularアプリケーションではないためである可能性があります。 FAQ詳しくは https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular

ロケーター付きの要素を待つ間-ロケーター:By(css selector、[data-e2e = 'scroll-to-offer'])

要素はページに存在します(手動で確認しました)が、分度器はまだタイムアウトします。

19
magnattic

同様の問題がありました Testability は不安定で、pendingMacroTasksがいくつかあるということしか知りませんでした。これらのタスクをローカライズするのは確かに少しトリッキーです(コードベース全体を調べてsetTimeoutを探すことはありません)。
しかし、最終的にはなんとかこれを行うことができました。

比較的シンプルなソリューション

最初にできることは、ChromeでDev Toolsを開き、_Ctrl+O_を押し、zone.jsと入力してEnterを押します。
これにより、zone.jsソースファイル(TypeScriptではなく、まだ何か)が開きます。
内側zone.js_Zone.prototype.runTask_を探し、このメソッド内にブレークポイントを置きます。
アプリケーションのロード後にブレークポイントを有効にします。そうしないと、何度もヒットします。

Testabilityが安定していない場合、おそらくそれ自体を再スケジュールするrepetitiveマクロタスクがあることを意味します。少なくともそれは私の場合でした。
この場合、アプリケーションがロードされた後、ブレークポイントはX回ごとにヒットします。

ブレークポイントに到達したら、_task.callback.[[FunctionLocation]]_に移動すると、(おそらく)setTimeoutまたはsetIntervalに移動します。
修正するには outside of Angular zone

少しトリッキーなソリューション

これにはZone.jsコードの微調整が含まれますが、より永続的なデバッグ情報が提供されます。

  1. _node_modules/zone.js/dist/zone.js_に移動します。
  2. ゾーンのコンストラクター関数を探します:function Zone(parent, zoneSpec)
  3. 次の内部を追加します:_this._tasks = {}_
  4. グローバルスコープにカウンター変数を追加:_let counter = 0_
  5. _Zone.prototype.scheduleTask_を探し、this._updateTaskCount(task,1)の呼び出しの直前に次の行を追加します。

    _task.id = counter++;
    this._tasks[task.id] = task;
    _
  6. _Zone.prototype.scheduleTask_を探し、this._updateTaskCount(task,-1)の呼び出しの直前に次の行を追加します。

    _delete this._tasks[task.id]
    _
  7. アプリケーションを再コンパイルして実行します

上記の調整を行ったとすると、次のような保留中のタスクにいつでもアクセスできます。

_tasks = Object.values(window.getAllAngularTestabilities()[0]._ngZone._inner._tasks)
_

テスト容易性の状態に影響する保留中のすべてのマクロタスクを取得するには:

_tasks.filter(t => t.type === 'macroTask' && t._state === 'scheduled')
_

その後、前のソリューションと同様に、_.callback.[[FunctionLocation]]_を確認し、Angularゾーンの外で実行して修正します。

17
JeB

分度器の非同期タスクを追跡する特定の方法はありません。あなたがするかもしれないことは、どの非同期タスクがフローをブロックしているのかを調査することです。テストする場合、デバッグには2つの主な手がかりがあります。アプリコードの非同期タスクとテストの非同期タスクです。

テストで、ジャスミンのようなものを使用している場合、jasmine.DEFAULT_TIMEOUT_INTERVAL;

とにかく、起動時とコールバック時にすべての非同期タスクのロギングを開始する以外に、これをデバッグするためのより良いオプションはありません。

1
Francisco

ベルコフ、

あなたが提供する機能を使用してタスクリストを取得するには、本当にあなたの助けが必要です。

import 'zone.js/dist/task-tracking'を追加しました。 AppModule.tsのコンストラクタメソッドにpolyfills.ts以下のコードを追加します。エラーCannot find name 'moduleInstance'.がスローされます

// app.module.ts

const ngZone = moduleInstance.injector.get(NgZone);
setInterval(() => {
    var taskTrackingZone = (<any>ngZone)._inner.getZoneWith("TaskTrackingZone");
    if (!taskTrackingZone) {
        throw new Error("'TaskTrackingZone' zone not found! Have you loaded 'node_modules/zone.js/dist/task-tracking.js'?");
    }
    var tasks: any[] = taskTrackingZone._properties.TaskTrackingZone.getTasksFor("macroTask");
    tasks = _.clone(tasks);
    if (_.size(tasks) > 0) {
        console.log("ZONE pending tasks=", tasks);
    }
}, 1000);

可能であれば、実際の例を教えてください。それはあなたの大きな助けになります。

ありがとうございました、

ジグネシュラヴァル

CC:@ hodossy-szabolcs

0
Jignesh Raval

JeBは way を提案する素晴らしい仕事をしました(いくつかの解決策は何もないよりはましです)。実際、保留中のタスクのリストを取得する方法がありますパッチを適用せずにzone.jsファイル。 angularソース: https://github.com/angular/angular/blob/master/packages/core/src/zone/ng_zone.ts #L134

方法は次のとおりです。

  1. node_modules/zone.js/dist/task-tracking.jsの後にzone.jsファイルをインポート
  2. 次に、コードでNgZoneインスタンスを取得し、次のように使用します
import * as _ from "lodash";
...
const ngZone = moduleInstance.injector.get(NgZone);
setInterval(() => {
    var taskTrackingZone = (<any>ngZone)._inner.getZoneWith("TaskTrackingZone");
    if (!taskTrackingZone) {
        throw new Error("'TaskTrackingZone' zone not found! Have you loaded 'node_modules/zone.js/dist/task-tracking.js'?");
    }
    var tasks: any[] = taskTrackingZone._properties.TaskTrackingZone.getTasksFor("macroTask");
    tasks = _.clone(tasks);
    if (_.size(tasks) > 0) {
        console.log("ZONE pending tasks=", tasks);
    }
}, 1000);

0