Có phương pháp nào để xóa các phiên bản .then
JavaScript Promise
không?
Tôi đã viết một khung kiểm tra JavaScript trên QUnit . Khung chạy các bài kiểm tra một cách đồng bộ bằng cách chạy từng cái trong một Promise
. (Xin lỗi vì độ dài của khối mã này. Tôi đã nhận xét nó tốt nhất có thể, vì vậy nó cảm thấy bớt tẻ nhạt hơn.)
/* 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);
});
});
}
Nếu bài kiểm tra hết thời gian chờ, Promise hết thời gian chờ của tôi sẽ xuất assert.fail()
hiện trong bài kiểm tra để bài kiểm tra được đánh dấu là không thành công, điều này là tốt và tốt, nhưng bài kiểm tra vẫn tiếp tục chạy vì bài kiểm tra Promise ( result
) vẫn đang chờ giải quyết.
Tôi cần một cách tốt để hủy bỏ bài kiểm tra của mình. Tôi có thể làm điều đó bằng cách tạo một trường trên mô-đun khuôn khổ this.cancelTest
hoặc thứ gì đó và kiểm tra mọi thứ thường xuyên (ví dụ: ở đầu mỗithen()
lần lặp) trong thử nghiệm xem có hủy bỏ hay không. Tuy nhiên, lý tưởng nhất là tôi có thể sử dụng $$(at).on("timeout", /* something here */)
để xóa các then()
s còn lại trên result
biến của mình , để không có phần còn lại của thử nghiệm nào được chạy.
Có một cái gì đó như thế này tồn tại?
Cập nhật nhanh
Tôi đã thử sử dụng Promise.race([result, at.promise])
. Nó không hoạt động.
Cập nhật 2 + nhầm lẫn
Để bỏ chặn tôi, tôi đã thêm một vài dòng với mod.cancelTest
/ polling trong ý tưởng thử nghiệm. (Tôi cũng đã loại bỏ trình kích hoạt sự kiện.)
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);
});
Tôi đã đặt một điểm ngắt trong catch
câu lệnh, và nó đang bị tấn công. Điều khiến tôi bối rối bây giờ làthen()
câu lệnh không được gọi. Ý tưởng?
Cập nhật 3
Đã tìm ra điều cuối cùng. fn.call()
đã đưa ra một lỗi mà tôi không bắt được, vì vậy lời hứa kiểm tra bị từ chối trước khi at.promise.catch()
có thể giải quyết nó.
Prex
thư viện để hủy bỏ lời hứa.