.then
Bir JavaScript’in ’lerini temizlemek için bir yöntem var mıPromise
örneğinin ' ?
QUnit'in üstüne bir JavaScript test çerçevesi yazdım . Çerçeve, her birini bir Promise
. (Bu kod bloğunun uzunluğu için özür dilerim. Elimden geldiğince yorum yaptım, bu yüzden daha az sıkıcı geliyor.)
/* 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);
});
});
}
Bir test zaman aşımına uğrarsa, benim zaman aşımı Promise assert.fail()
, testin başarısız olarak işaretlenmesini sağlayacak şekilde teste girecektir, bu tamamen iyi ve iyidir, ancak test Promise ( result
) hala çözülmeyi beklediği için test çalışmaya devam eder.
Testimi iptal etmek için iyi bir yola ihtiyacım var. Bunu, çerçeve modülünde this.cancelTest
veya başka bir şeyde bir alan oluşturarak then()
ve test içinde her seferinde (örneğin her yinelemenin başında ) iptal edip etmemeyi kontrol ederek yapabilirim . Ancak ideal olarak, $$(at).on("timeout", /* something here */)
kalan then()
e- postaları temizlemek için kullanabilirim .result
değişkenimde , böylece testin geri kalanının hiçbiri çalıştırılmaz.
Böyle bir şey var mı?
Hızlı güncelleme
Kullanmayı denedim Promise.race([result, at.promise])
. İşe yaramadı.
Güncelleme 2 + kafa karışıklığı
Engelimi kaldırmak için mod.cancelTest
, test fikrine / yoklama ile birkaç satır ekledim . (Olay tetikleyicisini de kaldırdım.)
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);
});
İfadede bir kesme noktası belirledim catch
ve vuruluyor. Şimdi kafamı karıştıran şey şu kithen()
ifadenin çağrılmaması. Fikirler?
Güncelleme 3
Son şeyi çözdüm. fn.call()
yakalayamadığım bir hata fırlatıyordu, bu yüzden test sözü, çözemeden önce reddediyordu at.promise.catch()
.