dx_*_*_dt 88 javascript promise cancellation es6-promise
有没有清除.then
JavaScript Promise
实例的方法?
我在QUnit上编写了一个JavaScript测试框架.框架通过在a中运行每个框架来同步运行测试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);
});
});
}
Run Code Online (Sandbox Code Playgroud)
如果测试超时,我的超时Promise将assert.fail()
在测试中,以便测试被标记为失败,这一切都很好,但测试继续运行,因为测试Promise(result
)仍在等待解决它.
我需要一个好方法取消我的测试.我可以通过在框架模块上创建一个字段来完成它this.cancelTest
,并在测试中经常检查(例如在每次then()
迭代开始时)是否取消.但是,理想情况下,我可以使用$$(at).on("timeout", /* something here */)
清除变量then()
上剩余的s result
,这样就不会运行其余的测试.
这样的事情存在吗?
我试过用Promise.race([result, at.promise])
.它没用.
为了解锁我,我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);
});
Run Code Online (Sandbox Code Playgroud)
我在catch
声明中设置了一个断点,它正被击中.我现在感到困惑的是,then()
声明没有被调用.想法?
想出最后一件事. fn.call()
抛出了一个我没有抓到的错误,因此测试承诺在拒绝之前at.promise.catch()
就可以解决它.
Ber*_*rgi 58
有没有一种清除
.then
JavaScript Promise实例的方法?
不.至少在ECMAScript 6中没有.Promise(和他们的then
处理程序)默认是不可取消的(不幸的是).关于如何以正确的方式进行es-discuss(例如这里)的讨论有一些讨论,但无论采用何种方法,它都不会落在ES6中.
目前的观点是子类化将允许使用您自己的实现创建可取消的承诺(不确定它将如何工作).
直到语言委员会找到最好的方法(ES7希望?),你仍然可以使用userland Promise实现,其中许多功能取消.
目前的讨论在https://github.com/domenic/cancelable-promise和https://github.com/bergus/promise-cancellation草案中进行.
Mic*_*aev 48
虽然在ES6中没有标准的方法,但是有一个名为Bluebird的库来处理这个问题.
还有一种推荐的方法被描述为反应文档的一部分.它看起来与您在第2次和第3次更新中的内容类似.
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then((val) =>
hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
);
promise.catch((error) =>
hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
const cancelablePromise = makeCancelable(
new Promise(r => component.setState({...}}))
);
cancelablePromise
.promise
.then(() => console.log('resolved'))
.catch((reason) => console.log('isCanceled', reason.isCanceled));
cancelablePromise.cancel(); // Cancel the promise
Run Code Online (Sandbox Code Playgroud)
取自:https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
可以在 的帮助下取消 Promise AbortController
。
那么是否有清除方法: 是的,您可以拒绝带有
AbortController
对象的承诺,然后promise
将绕过所有 then 块并直接转到 catch 块。
例子:
import "abortcontroller-polyfill";
let controller = new window.AbortController();
let signal = controller.signal;
let elem = document.querySelector("#status")
let example = (signal) => {
return new Promise((resolve, reject) => {
let timeout = setTimeout(() => {
elem.textContent = "Promise resolved";
resolve("resolved")
}, 2000);
signal.addEventListener('abort', () => {
elem.textContent = "Promise rejected";
clearInterval(timeout);
reject("Promise aborted")
});
});
}
function cancelPromise() {
controller.abort()
console.log(controller);
}
example(signal)
.then(data => {
console.log(data);
})
.catch(error => {
console.log("Catch: ", error)
});
document.getElementById('abort-btn').addEventListener('click', cancelPromise);
Run Code Online (Sandbox Code Playgroud)
html
<button type="button" id="abort-btn" onclick="abort()">Abort</button>
<div id="status"> </div>
Run Code Online (Sandbox Code Playgroud)
注意:需要添加 polyfill,并非所有浏览器都支持。
现场示例
我真的很惊讶,没有人提到Promise.race
这个候选人:
const actualPromise = new Promise((resolve, reject) => { setTimeout(resolve, 10000) });
let cancel;
const cancelPromise = new Promise((resolve, reject) => {
cancel = reject.bind(null, { canceled: true })
})
const cancelablePromise = Object.assign(Promise.race([actualPromise, cancelPromise]), { cancel });
Run Code Online (Sandbox Code Playgroud)
const makeCancelable = promise => {
let rejectFn;
const wrappedPromise = new Promise((resolve, reject) => {
rejectFn = reject;
Promise.resolve(promise)
.then(resolve)
.catch(reject);
});
wrappedPromise.cancel = () => {
rejectFn({ canceled: true });
};
return wrappedPromise;
};
Run Code Online (Sandbox Code Playgroud)
用法:
const cancelablePromise = makeCancelable(myPromise);
// ...
cancelablePromise.cancel();
Run Code Online (Sandbox Code Playgroud)
阻止promise的执行实际上是不可能的,但是你可以劫持reject并从promise本身调用它。
class CancelablePromise {
constructor(executor) {
let _reject = null;
const cancelablePromise = new Promise((resolve, reject) => {
_reject = reject;
return executor(resolve, reject);
});
cancelablePromise.cancel = _reject;
return cancelablePromise;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
const p = new CancelablePromise((resolve, reject) => {
setTimeout(() => {
console.log('resolved!');
resolve();
}, 2000);
})
p.catch(console.log);
setTimeout(() => {
p.cancel(new Error('Messed up!'));
}, 1000);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
74549 次 |
最近记录: |