【问题标题】:Is it ok not to use reject in a Promise?可以不在 Promise 中使用拒绝吗?
【发布时间】:2019-03-20 05:45:08
【问题描述】:

可以构造一个从不拒绝的 Promise 吗?我的意思是这是某种反模式还是可以接受的?让我用一个例子来说明这一点。我有一个类 ModifyURL,它由许多方法组成,每个方法对 URI 字符串数组执行一些操作并返回一个 Promise。部分实现如下所示。

class ModifyURL {
    constructor() {

    }
    /**
     * Remove empty and invalid urls
     * @param {object} object containing arrays of links
     *
     * @return {object} object containing arrays of valid links
     */
    removeInvalid(data) {
        return new Promise((resolve,reject)=>{
            for (let key in data) {
                data[key] = data[key].filter( function(item) {
                    return !(item == '#' || !item || item == ' ');
                });
            }
            resolve(data)
        });
    }

    /**
     * Remove duplicates
     * @param {object} object containing arrays of links
     *
     * @return {object} object containing arrays of unique links
     */
    removeDuplicates(data) {
        return new Promise((resolve,reject)=>{
            for (let key in data) {
                data[key] = data[key].filter(function (item, pos) {
                    return data[key].indexOf(item) == pos;
                })
            }
            resolve(data)
        });
    }
    /**
     * Add full hostname to relative urls.
     * @param {object}  object containing arrays of links
     * @param {string} hostname to be added if link is relative
     *
     * @return  {object} object containing arrays of absolute links
     */
    fixRelativeLinks(data,hostname) {
        if(typeof data === 'object'){
            return new Promise((resolve,reject)=>{
                for (let key in data) {
                    data[key].forEach((v, i) => {
                        if(data[key][i]){
                            data[key][i] = URL.resolve(hostname, data[key][i])
                        }
                    })
                }
                resolve(data)
            })
        }
    }
}

稍后我将这些 Promise 链接起来,它工作正常。

                            modifyURL.removeInvalid(data).then(res=>{
                                return res
                            })
                            .then(()=>{
                                return modifyURL.fixRelativeLinks(data, res.request.href)
                            })
                            .then(modifyURL.removeDuplicates).then(res=>{
                                onSuccess(res)
                            }).catch(err=>{console.log(err)})

正如你所注意到的,我不使用 reject,感觉有点奇怪。原因是最后我需要接收一些数据。即使链中的某些 Promise 未能完成他们的任务,我也需要最终 resolve 使用我的 URI 字符串数组。这就是我不拒绝的原因,因为它破坏了我的Promise链。但是如果没有 reject,我将失去正确跟踪错误的能力。处理此类任务的正确方法是什么?

【问题讨论】:

  • 如果你从不做任何异步操作,那么 Promise 的意义何在?这种将所有内容都包装在 Promise 中的方式对我来说看起来很糟糕。
  • 如果您的代码是同步的,请将其保留为函数而不是承诺;您仍然可以将结果链接到 promise 链中,也可以将其用作普通函数。
  • 如果Promise构造函数的执行器函数(接受resolvereject参数的函数)抛出错误,则忽略你没有做任何异步的事实,构造的promise隐式转换到拒绝状态,所以你很好。但是,如果可能发生不会抛出的错误,或者在构造函数中创建的异步回调的承诺链,您需要检查这些条件并使用您自己的用户定义的错误调用 reject()。事实上,如果你的构造函数中有任何 Promise,你就不应该使用它。
  • @przemoo83 不,这样不行。如果 API 或网络出现故障,您绝对应该拒绝该承诺。否则你的调用者将永远无法处理错误。
  • @przemoo83 “保持 Promise 链正常工作”到底是什么意思?你能举个例子吗?你应该只在链的中间使用.catch(e => substituteResult),它会返回一个新的promise,即使之前的promise失败了,也会用替代结果来实现。

标签: javascript promise


【解决方案1】:

可以构造一个从不拒绝的 Promise 吗?

是的,没关系。如果操作中没有可能出现的错误,那么只要 promise 解决就好了。

我的意思是这是某种反模式还是可以接受的?

拥有一个从不拒绝的承诺是完全可以接受的(假设有一些代码路径可以解决)。例如,您可以编写一个在特定延迟后解析承诺的函数,如下所示:

function delay(t, v) {
    return new Promise(resolve => {
        setTimeout(resolve, t, v);
    });
}

我有一个类 ModifyURL,它由许多方法组成,每个方法对 URI 字符串数组执行一些操作并返回一个 Promise。部分实现如下所示。

这些都是同步函数。它们不需要被包裹在 Promise 中,也不应该被包裹在 Promise 中。 Promise 用于跟踪异步操作。在将它们与纯同步代码一起使用时,它们只会创建比必要更复杂的代码。

虽然可以用 Promise 包装同步操作(正如您所拥有的),但我将其称为反模式,因为它使代码比仅使用普通同步编码模式(您只需一个接一个地调用多个函数)复杂得多或者,如果它们都对相同的数据进行操作,则将这些函数设为对象上的所有方法,并一个接一个地调用它们。

正如你所注意到的,我不使用拒绝,感觉有点奇怪。原因是最后我需要接收一些数据。

首先,您在这里误用了同步代码的承诺。但是,通常使用异步代码,您的代码可以决定出现错误时会发生什么。您可以让拒绝传播并停止链条,或者您可以在本地捕获拒绝并将其更改为您希望链条继续的任何内容,并且链条不会知道发生任何错误。这取决于您和您的代码。你完全可以控制它。

即使链中的某些 Promise 未能完成他们的任务,我也需要最终用我的 URI 字符串数组来解决。

这只是要进行适当的本地错误处理,以便您在本地捕获并处理任何错误,以便您可以继续处理其余数据并返回已成功处理的数据。这在概念上与使用带有同步代码的 try/catch 在本地捕获错误没有什么不同,这样您就可以捕获它们、处理它们,但它是适当的,然后继续其余的工作。

这就是我不拒绝的原因,因为它破坏了我的 Promise 链。但是如果没有拒绝,我将失去正确跟踪错误的能力。处理此类任务的正确方法是什么?

对此并没有真正的通用答案,因为它实际上取决于特定的应用程序及其正在做什么以及您希望如何将结果和错误都传达回来。有时您会在第一个错误时中止链(快速失败)。有时您会跳过错误并返回成功的结果。有时您会返回一组结果和一组错误。有时您返回一个同时包含结果和错误的数组,并以数据格式提供一些方法来了解哪个是错误,哪个是成功的结果。而且,您可以发明任意多种其他方式来传达结果和错误。

【讨论】:

  • 感谢您提供如此详细而全面的答案。你澄清了我难以理解的问题。当然,我提供的示例完全滥用了 Promise 机制,也感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
  • 2018-08-17
  • 2018-08-26
  • 1970-01-01
  • 2017-11-20
  • 2021-06-06
相关资源
最近更新 更多