มีวิธีการล้างอินสแตนซ์.then
JavaScript 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);
});
});
}
หากการทดสอบหมดเวลาสัญญาหมดเวลาของฉันจะassert.fail()
ทำการทดสอบเพื่อให้การทดสอบถูกทำเครื่องหมายว่าล้มเหลวซึ่งทั้งหมดนั้นดีและดี แต่การทดสอบยังคงดำเนินต่อไปเนื่องจากการทดสอบ Promise ( result
) ยังคงรอการแก้ไขอยู่
ฉันต้องการวิธีที่ดีในการยกเลิกการทดสอบของฉัน ฉันสามารถทำได้โดยการสร้างฟิลด์ในโมดูลเฟรมเวิร์กthis.cancelTest
หรือบางสิ่งบางอย่างและตรวจสอบทุก ๆ ครั้ง (เช่นที่จุดเริ่มต้นของthen()
การทำซ้ำแต่ละครั้ง) ภายในการทดสอบว่าจะยกเลิกหรือไม่ อย่างไรก็ตาม$$(at).on("timeout", /* something here */)
ตามหลักการแล้วฉันสามารถใช้เพื่อล้างค่าthen()
s ที่เหลือบนresult
ตัวแปรของฉันเพื่อไม่ให้การทดสอบที่เหลือถูกเรียกใช้
สิ่งนี้มีอยู่จริงหรือไม่?
อัปเดตด่วน
ฉันลองใช้Promise.race([result, at.promise])
. มันไม่ได้ผล
อัปเดต 2+ ความสับสน
ในการปลดบล็อกฉันฉันได้เพิ่มสองสามบรรทัดด้วยmod.cancelTest
/ การสำรวจความคิดเห็นภายในแนวคิดการทดสอบ (ฉันลบทริกเกอร์เหตุการณ์ด้วย)
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
คิดสิ่งสุดท้ายออก fn.call()
กำลังแสดงข้อผิดพลาดซึ่งฉันไม่ได้จับดังนั้นคำสัญญาในการทดสอบจึงถูกปฏิเสธก่อนที่at.promise.catch()
จะแก้ไขได้