Apakah ada metode untuk menghapus instance .then
JavaScript Promise
?
Saya telah menulis kerangka pengujian JavaScript di atas QUnit . Kerangka kerja menjalankan pengujian secara sinkron dengan menjalankan masing-masing pengujian di a Promise
. (Maaf untuk panjang blok kode ini. Saya berkomentar sebaik mungkin, jadi rasanya tidak terlalu membosankan.)
/* 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);
});
});
}
Jika tes habis waktu, Janji batas waktu saya akan assert.fail()
di tes sehingga tes ditandai sebagai gagal, yang semuanya baik dan bagus, tetapi tes terus berjalan karena tes Promise ( result
) masih menunggu untuk menyelesaikannya.
Saya perlu cara yang baik untuk membatalkan tes saya. Saya dapat melakukannya dengan membuat bidang pada modul kerangka kerja this.cancelTest
atau sesuatu, dan memeriksa sesering mungkin (misalnya pada awal setiap then()
iterasi) dalam pengujian apakah akan membatalkan. Namun, idealnya, saya dapat menggunakan $$(at).on("timeout", /* something here */)
untuk menghapus sisa then()
s pada result
variabel saya , sehingga tidak ada sisa pengujian yang dijalankan.
Apakah ada yang seperti ini?
Pembaruan Cepat
Saya mencoba menggunakan Promise.race([result, at.promise])
. Tidak berhasil.
Perbarui 2 + kebingungan
Untuk membebaskan saya, saya menambahkan beberapa baris dengan mod.cancelTest
/ polling di dalam ide pengujian. (Saya juga menghapus pemicu acara.)
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);
});
Saya menetapkan breakpoint dalam catch
pernyataan tersebut, dan itu dipukul. Yang membingungkan saya sekarang adalah then()
pernyataan itu tidak dipanggil. Ide ide?
Perbarui 3
Pikir hal terakhir. fn.call()
melakukan kesalahan yang tidak saya tangkap, jadi janji pengujian ditolak sebelum at.promise.catch()
bisa menyelesaikannya.
Prex
perpustakaan untuk pembatalan janji.