Внутри исполнителя обещания вы не можете получить доступ к обещанию. Он еще не был назначен ни для чего, что может достичь ваш код.
Итак, у вас есть два варианта.
- Вы можете поместить свой код очистки вне исполнителя, чтобы получить доступ к возвращенному обещанию с помощью
p.finally()
. Затем вам также придется отслеживать ваши ресурсы за пределами исполнителя (что, возможно, неудобно).
- Вы можете заменить обратные вызовы
resolve()
и reject()
вашей собственной заглушкой, которая выполняет очистку, а затем вызывает фактические resolve()
или reject()
.
- Вы можете использовать Отложенный объект, который позволяет вам вызывать разрешение / отклонение извне исполнителя обещания, таким образом предоставляя вам доступ к
p.finally()
, resolve()
и reject()
- все в одной и той же области действия (которая действительно является источником оригинальный вызов).
Вот пример варианта # 2:
return new Promise(function(rv, rj) {
// have to try/catch here because an execption will automatically reject
// without us having seen it
try {
// declare wrappers that should be called by code in this executor
// do not call rv() and rj() directly
function resolve(arg) {
finally();
rv(arg);
}
function reject(arg) {
finally();
rj(arg);
}
// cleanup code that is only ever called once
let finallyCalled = false;
function finally() {
if (!finallyCalled) {
clearTimeout(to);
finallyCalled = true;
}
}
const to = setTimeout(function(){
});
// elsewhere in this executor it should call resolve() or reject()
} catch(e) {
reject(e);
}
});
Вот пример варианта № 3.
Отложенные объекты, как правило, не рекомендуется, но они дают вам доступ к .finally()
, resolve()
и reject()
- все в одной области, что делает некоторые вещи чище (например, то, что вы пытаетесь сделать).
Сначала простая оболочка обещания, которая дает нам отложенный объект:
// can be used as either:
// let d = Promise.Deferred();
// let d = new Promise.Deferred();
// d.then(...)
// d.resolve(x);
// d.finally(...)
Promise.Deferred = function() {
if (!(this instanceof Promise.Deferred)) {
return new Promise.Deferred();
}
let p = this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
this.then = p.then.bind(p);
this.catch = p.catch.bind(p);
this.finally = p.finally.bind(p);
}
Тогда вы можете использовать это так:
// usage
function yourFunction() {
let d = new Promise.Deferred();
const to = setTimeout(...);
// other code here that will call d.resolve() or d.reject()
// cleanup code
d.finally(function() {
clearTimeout(to);
});
return d.promise;
}