[解決済み] vanilla ECMAScript 6 の Promise チェーンをキャンセルする
質問
をクリアする方法はありますか?
.then
をクリアする方法はありますか?
Promise
のインスタンスですか?
の上にJavaScriptのテストフレームワークを書きました。
QUnit
. このフレームワークでは、テストを同期的に実行するために、それぞれのテストを
Promise
. (このコードブロックの長さは申し訳ありません。 できる限りコメントしたので、面倒に感じないと思います)。
/* Promise extension -- used for easily making an async step with a
timeout without the Promise knowing anything about the function
it's waiting on */
$$.extend(Promise, {
asyncTimeout: function (timeToLive, errorMessage) {
var error = new Error(errorMessage || "Operation timed out.");
var res, // resolve()
rej, // reject()
t, // timeout instance
rst, // reset timeout function
p, // the promise instance
at; // the returned asyncTimeout instance
function createTimeout(reject, tempTtl) {
return setTimeout(function () {
// triggers a timeout event on the asyncTimeout object so that,
// if we want, we can do stuff outside of a .catch() block
// (may not be needed?)
$$(at).trigger("timeout");
reject(error);
}, tempTtl || timeToLive);
}
p = new Promise(function (resolve, reject) {
if (timeToLive != -1) {
t = createTimeout(reject);
// reset function -- allows a one-time timeout different
// from the one original specified
rst = function (tempTtl) {
clearTimeout(t);
t = createTimeout(reject, tempTtl);
}
} else {
// timeToLive = -1 -- allow this promise to run indefinitely
// used while debugging
t = 0;
rst = function () { return; };
}
res = function () {
clearTimeout(t);
resolve();
};
rej = reject;
});
return at = {
promise: p,
resolve: res,
reject: rej,
reset: rst,
timeout: t
};
}
});
/* framework module members... */
test: function (name, fn, options) {
var mod = this; // local reference to framework module since promises
// run code under the window object
var defaultOptions = {
// default max running time is 5 seconds
timeout: 5000
}
options = $$.extend({}, defaultOptions, options);
// remove timeout when debugging is enabled
options.timeout = mod.debugging ? -1 : options.timeout;
// call to QUnit.test()
test(name, function (assert) {
// tell QUnit this is an async test so it doesn't run other tests
// until done() is called
var done = assert.async();
return new Promise(function (resolve, reject) {
console.log("Beginning: " + name);
var at = Promise.asyncTimeout(options.timeout, "Test timed out.");
$$(at).one("timeout", function () {
// assert.fail() is just an extension I made that literally calls
// assert.ok(false, msg);
assert.fail("Test timed out");
});
// run test function
var result = fn.call(mod, assert, at.reset);
// if the test returns a Promise, resolve it before resolving the test promise
if (result && result.constructor === Promise) {
// catch unhandled errors thrown by the test so future tests will run
result.catch(function (error) {
var msg = "Unhandled error occurred."
if (error) {
msg = error.message + "\n" + error.stack;
}
assert.fail(msg);
}).then(function () {
// resolve the timeout Promise
at.resolve();
resolve();
});
} else {
// if test does not return a Promise, simply clear the timeout
// and resolve our test Promise
at.resolve();
resolve();
}
}).then(function () {
// tell QUnit that the test is over so that it can clean up and start the next test
done();
console.log("Ending: " + name);
});
});
}
テストがタイムアウトした場合、私のタイムアウトPromiseは
assert.fail()
を実行し、テストは失敗とマークされます。それはそれで良いのですが、テストのプロミス (
result
) がまだ解決するのを待っているからです。
私はテストをキャンセルする良い方法が必要です。 私はフレームワークモジュールにフィールドを作成することによってそれを行うことができます
this.cancelTest
フィールドを作成し、頻繁にチェックします (たとえば、それぞれの
then()
の繰り返しの最初) にチェックします。 しかし、理想を言えば、私は
$$(at).on("timeout", /* something here */)
をクリアして、残りの
then()
をクリアする必要があります。
result
変数に追加することで、残りのテストが実行されないようにします。
このようなものは存在するのでしょうか?
クイックアップデート
を使ってみました。
Promise.race([result, at.promise])
. うまくいきませんでした。
アップデート2+混乱
ブロックを解除するために、数行で
mod.cancelTest
/pollingをテストアイデア内に追加しました。 (イベントトリガーも削除しました)。
return new Promise(function (resolve, reject) {
console.log("Beginning: " + name);
var at = Promise.asyncTimeout(options.timeout, "Test timed out.");
at.promise.catch(function () {
// end the test if it times out
mod.cancelTest = true;
assert.fail("Test timed out");
resolve();
});
// ...
}).then(function () {
// tell QUnit that the test is over so that it can clean up and start the next test
done();
console.log("Ending: " + name);
});
にブレークポイントを設定しました。
catch
ステートメントにブレークポイントを設定し、それがヒットしています。 今、私を混乱させているのは
then()
ステートメントが呼び出されないことです。 アイデアはありますか?
アップデート 3
最後の1つを把握した。
fn.call()
は私がキャッチしていないエラーを投げていたので、テストプロミスは
at.promise.catch()
がそれを解決する前に拒否していました。
どのように解決するのですか?
<ブロッククオート
をクリアする方法はありますか?
.then
をクリアする方法はありますか?
いいえ、少なくとも ECMAScript 6 ではそうではありません。プロミス(とその
then
ハンドラ) はデフォルトでキャンセル不可です。
(残念ながら)
. es-discuss で少し議論されています (例.
ここで
など)で、正しい方法でこれを行う方法について少し議論されていますが、どのようなアプローチであれ、ES6に着地することはないでしょう。
現在の立場は、サブクラス化によって、独自の実装を使用してキャンセル可能な約束事を作成できるようになることです。 (それがどの程度うまくいくかはわからないが) .
言語委員会が最適な方法を見出すまで (ES7を希望?) が見つかるまでは、ユーザランドの Promise 実装を使うことができます。
現在の議論は https://github.com/domenic/cancelable-promise と https://github.com/bergus/promise-cancellation の下書き。
関連
-
vueのグローバルがscss(mixin)を導入。
-
JavaScriptの配列共通メソッド解説
-
vue ディレクティブ v-html と v-text
-
[解決済み] テスト
-
[解決済み】<select>で現在選択されている<option>をJavaScriptで取得するにはどうすればよいですか?
-
[解決済み] ECMAScript 6 オブジェクトを返す矢印関数
-
[解決済み] 明示的なプロミス構築のアンチパターンとそれを回避する方法とは?
-
[解決済み] オブジェクトがPromiseであるかどうかを判断するにはどうすればよいですか?
-
[解決済み] JavascriptのPromiseを関数スコープ外で解決する
-
[解決済み] .then()チェーンで以前のプロミス結果にアクセスするにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
vueネットワークリクエストソリューション ネイティブネットワークリクエストとjsネットワークリクエストライブラリ
-
Vueはランニングライト形式のテキストを水平方向にスクロールする機能を実装している
-
jQueryのコピーオブジェクトの説明
-
Vueのフィルタの説明
-
[解決済み】Node Version Manager のインストール - nvm コマンドが見つかりません。
-
[解決済み】ローカルファイルを開くことができません - Chrome: ローカルリソースの読み込みが許可されていない
-
[解決済み】JavaScriptの配列でforEachが関数でない不具合
-
[解決済み】React-Redux: アクションはプレーンオブジェクトでなければならない。非同期アクションにはカスタムミドルウェアを使用する
-
[解決済み】 env: node: macにそのようなファイルやディレクトリはありません
-
[解決済み】エラー。Ionic使用中にモジュール '../lib/utils/unsupported.js' が見つかりませんでした。