【问题标题】:Promise continues after error错误后承诺继续
【发布时间】:2018-07-17 00:44:37
【问题描述】:

我有一些异步代码需要在出错时停止但继续执行:

async saveCoupons({ state, rootState, dispatch, commit }) {
    const promises = []
    state.userCoupons.forEach(coupon => { 
        if (coupon.isNew && coupon.isUpdated) {
            // if the user is creating a new coupon
            promises.push(Vue.axios.post('/api_producer/coupons.json', coupon, { params: { token: coupon.token } }))
        } else if (!coupon.isNew && coupon.isUpdated) {
            // if the user is updating the coupon
            promises.push(Vue.axios.patch(`api_producer/coupons/${coupon.id}/`, coupon, { params: { token: coupon.token } }))
        }
    })
    try {
        await Promise.all(promises)
        dispatch('utilities/showModal', 'success', { root: true })
        dispatch('fetchProducerCoupons')
    } catch (err) {
        let couponToken = err.request.responseURL.split('token=')[1]
        commit('ADD_ERROR_ON_COUPON', couponToken)
        console.log(err)
    }
}

这就是代码当前的结构,它可以工作,但我意识到这很糟糕。我需要做的是停止执行

dispatch('utilities/showModal', 'success', { root: true })
dispatch('fetchProducerCoupons')

如果其中一个 api 调用失败。我想在 forEach 中捕获错误,所以我已经有了可用的项目,我可以立即将错误添加到它,而不是之后再做(这就是我现在用 { params: { token: coupon.token } } 做的事情。

【问题讨论】:

  • 请求需要并行触发还是可以一个接一个地触发?
  • 不,这并不重要。只要我可以直接从 forEach 中捕获调用错误,我就可以将错误附加到项目上,然后将其显示在前端。如果它成功了,那么它所做的只是显示成功模式,而不是通过再次获取它们来刷新项目
  • 为每个 Promise 调用添加一个 .catch 并将您需要的参数“抛出”到错误处理程序。
  • @LuizChagasJr 它仍然以这种方式执行底部的其余代码,除非我做错了什么。你真的能写下来吗?
  • 如果promises 中的任何一个被拒绝,那么await 将触发异常并且您的调度将不会被执行。 api调用失败时promise不会被拒绝吗?

标签: javascript asynchronous vue.js promise async-await


【解决方案1】:

我认为最好的方法是将 Vue.axios 请求包装到您自己的 Promise 中。然后,如果请求失败,您的错误中就会包含优惠券令牌。

类似

const promises = [];

promises.push(
  Vue.axios.post('/api_producer/coupons.json', coupon)
    .catch(() => { throw new Error(coupon.token) }));
    
Promise.all(promises).catch(tokens => {
  tokens.forEach(token => {
    // Commit/handle errorous token
  });
});

【讨论】:

  • 是的,这行得通。我只在 api 调用中使用catch,因为我不需要在成功时做任何事情,并且在Promise.all(promises) 中我有then() 在代码末尾执行两个函数。我会再次发布我所拥有的。我想知道是否有一种方法可以使用 await/async 来完成所有这些操作,我比 Promises 更喜欢
  • @Bergi,你是什么意思?
  • @Giacomo,当然可以。您只需要一个“全局”变量,它会在最后告诉您是否有任何调用失败,然后才执行您的 dispatch 操作。
  • @Bergi,好的,我明白你的意思。正如我对 OP 的理解一样,他想在 catch 中访问 coupon.token。但是,如果Vue.axios 请求失败,他仍然不知道它是哪个令牌。因此,我将它包装到另一个 Promise 中。还是由Vue.axios 处理?
【解决方案2】:

您可以将您的 api 调用包装在另一个 Promise 中并检查状态。像这样的:

promises.push(

  new Promise((resolve, reject) => {

    Vue.axios.post('/api_producer/coupons.json', coupon, { params: { token: coupon.token } })
    .then((response) => {
      if (response.status !== 200) {
        coupon.error = true;
        reject();
      } else {
        resolve();
      }
    });

  })
);

reject 将阻止这两行代码被执行:

  dispatch('utilities/showModal', 'success', { root: true })
  dispatch('fetchProducerCoupons')  

【讨论】:

  • 但这仍然不允许我访问 forEach 中的错误,它必须在外部
  • 啊!!我也试过了,但我错过了new Promise,不明白为什么现在这是解决方案,但它正在工作
  • 我不知道这是一个反模式,感谢您引起我的注意
【解决方案3】:

感谢 Moritz Schmitz v. Hülst & sklingler93 的帮助,我重新构建了代码并且它正在工作。

我想知道是否有一种方法可以仅使用 async/await 来编写所有这些...如果有人有想法,很想看看 :)

saveCoupons({ state, rootState, dispatch, commit }) {
    const promises = []
    state.userCoupons.forEach(coupon => {          
        if (coupon.isNew && coupon.isUpdated) {
            // if the user is creating a new coupon
            promises.push(new Promise((resolve, reject) => {
                Vue.axios.post('/api_producer/coupons.json', coupon)
                    .then(response => resolve(response))
                    .catch(err => {
                        reject(err)
                        commit('ADD_ERROR_ON_COUPON', coupon.token)
                    })                        
            }))
        } else if (!coupon.isNew && coupon.isUpdated) {
            // if the user is updating the coupon
            promises.push(new Promise((resolve, reject) => {
                Vue.axios.patch(`api_producer/coupons/${coupon.id}/`, coupon)
                    .then(response => resolve(response))
                    .catch(err => {
                        reject(err)
                        commit('ADD_ERROR_ON_COUPON', coupon.token)
                    })
            }))
        }
    })
    Promise.all(promises)
        .then(() => {
            dispatch('utilities/showModal', 'success', { root: true })
            dispatch('fetchProducerCoupons')
        })
        .catch(err => console.error(err))
},

【讨论】:

  • 此代码无法运行。你数组中的承诺永远不会解决
  • Promise.all(promises)... 不负责吗? @Bergi
  • 没有。 Promise.all 除了返回的承诺之外,不履行任何承诺。在所有这些new Promise 执行器回调中,您永远不会调用resolvereject
  • 好的,我在每个新的 Promise 中添加了 .then(response => resolve(response))。是这样吗?
  • No。现在你只是忽略了错误。
猜你喜欢
  • 1970-01-01
  • 2021-05-31
  • 2021-05-21
  • 1970-01-01
  • 2019-04-03
  • 2018-10-02
  • 1970-01-01
  • 2021-08-11
相关资源
最近更新 更多