你能返回一个带有预定义finally的Promise吗?

问题描述 投票:0回答:4

我有一个返回 Promise 的函数。当我在

.then()
.catch()
块中使用完 Promise 后,我总是想执行相同的清理代码。我当前的设置是这样的:

const promiseWithFinally = () => {
  return new Promise((resolve, reject) => {
    // resolve or reject at some point
  }).finally(() => console.log('finally done'))
}

promiseWithFinally()
  .then(() => console.log('then done'))
  .catch(() => console.log('catch done'))

我想要发生的是首先记录

then done
catch done
,然后记录
finally done
。然而,它似乎以完全相反的顺序执行 - 当我在 5 秒超时后解析 Promise 时,
finally done
在 5 秒后首先被记录,然后立即
then done

我做错了什么或者一般可以这样做吗?我知道我可以将

.finally()
附加到每个单独的函数调用中,但由于它始终相同,我想将其放在函数定义中。

javascript promise
4个回答
1
投票

不,这是不可能的。最后用于在给定的承诺之后进行清理,而不是其

then
catch
方法。

您可以做的是将

then
catch
方法传递给将附加在
finally
之前的函数:

const promiseWithFinally = (chain) => {
  return new Promise((resolve, reject) => {
    // resolve or reject at some point
    setTimeout(resolve, 1000);
  }).then(chain.then, chain.catch).finally(() => console.log('finally done'))
}

promiseWithFinally({
  then: () => console.log('then done'),
  catch: () => console.log('catch done')
})


1
投票

简短回答

不,这是不可能的,因为你不能依赖于finally 何时运行。

更长的答案和可能的解决方案

代码

const cleanupFunc = () => {
  console.log('Cleaning up.');
  };

const someAsyncMethod = (thenFunc, catchFunc) => {
  new Promise(
    (resolve, reject) => {
      setTimeout(() => resolve(), 5000);
    },
  )
    .then((...args) => {
      try {
        thenFunc(...args);
      } catch (err) {
      }
      cleanupFunc();
    })
    .catch((...args) => {
      try {
        catchFunc(...args);
      } catch (err) {
      }
      cleanupFunc();
    });
};

someAsyncMethod((result) => console.log('Then done'), (err) => console.log('Catch done'));

说明

虽然不可能依赖于finally,但你可以做的是编写一个需要执行一些异步操作并返回promise的函数。在我的示例中,此操作等待 5 秒超时,但他也可以是返回 Promise 的异步 api 调用。

下一步是向异步操作返回的 Promise 添加 then 和 catch 调用,这两个调用都以 try 子句开头,在其中调用属于解析类型的回调参数(thenFunc 为 then,catchFunc 为 catch ) 后跟一个 catch,它不执行任何操作并以调用清理函数结束。通过这种方式,您可以确定无论在运行 then 或 catch 回调期间发生什么,都会调用清理函数。


0
投票

假设您知道该 Promise 的其余处理程序将同步附加,并且处理程序中的所有操作都是同步的,这是可能的,尽管有点 hacky。

只需让finally 处理程序在最后重新附加自身即可:

const promiseWithFinally = () => {
  const thisPromise = new Promise((resolve, reject) => {
    // Rejection example
    setTimeout(reject, 200);
  }).finally(() => {
    setTimeout(() => {
      thisPromise.finally(() => console.log('finally done')).catch(() => {});
    }, 0);
  });
  return thisPromise;
};

promiseWithFinally()
  .then(() => console.log('then done'))
  .catch(() => console.log('catch done'));
  


0
投票

有一个涉及承诺的解决方案。 需要注意的是,如果返回的 Promise 对象的用户执行类似的“hack”,它将不起作用。

const promise = new Promise((resolve, reject) => resolve());
promise.finally(() => promise.finally(() => console.log("cleanup")));
promise.then(() => console.log("do me first!"));

这个概念是,在 Promise 链中执行的第一个回调可以将任何它想要的内容附加到 Promise 链的末尾。当然,如果下一个回调做了同样的事情,你就不走运了,这是这种方法的局限性。

© www.soinside.com 2019 - 2024. All rights reserved.