将异步函数返回的Promise类型更改为其他类型

时间:2018-08-02 21:59:13

标签: node.js promise async-await parse-server

编辑-尽管答案中包含几个可行的解决方案,但我要指出,Parse JS SDK 2.0(以及因此的Parse-Server 3.0)已经发布,实际上删除了Parse.Promise。因此,最好的解决方案是换出Parse Promise实现并改为使用本机Promises。

我使用Parse-Server(最新版本2.8.2)作为后端。我已经很习惯诺言,并且在我的代码中根深蒂固。

不过,我已经开始使用异步/等待模式。但这在我现有的所有实现中都不能很好地发挥作用。

此示例将引发错误:

const promiseErrorTestHelper = async () => {
    return Parse.Promise.as();
}

Parse.Cloud.define('promiseErrorTest', async(req, res) => {
    promiseErrorTestHelper().always(
        res.success
    );
});

这个很好用:

const promiseErrorTestHelper = async () => {
    return Parse.Promise.as();
}

Parse.Cloud.define('promiseErrorTest', async(req, res) => {
    promiseErrorTestHelper().then(
        res.success
    );
});

在Parse-Server中,无论承诺是被拒绝还是已解决,.always()都用于传递回调函数。我在整个代码中都使用了此功能,并在重构某些功能以在添加新功能时使用异步/等待时发现了问题。

我理解问题在于异步函数将其结果包装在Promise中。因此,它将我的Parse.Promise转换为没有.always()方法的其他类型。

我是否有一种简单的方法可以替代async的功能以返回Parse.Promise?还是要使用异步/等待功能来重新处理always()呼叫?

2 个答案:

答案 0 :(得分:2)

您似乎无法更改从async函数返回的承诺类型。它是内置的以返回本机​​承诺,并且不可配置。这里有一个类似的讨论,关于如何使async函数返回Bluebird Promise here。结论是,如果要蓝鸟承诺,则不能这样做,必须包装async函数。


要在发生错误后继续,通常的方法是使用.catch()记录错误并且不重新抛出,从而“处理”错误:

someFunc().catch(err => {
    // handle the error, continue processing, changes promise chain to resolved
    console.log(err);
    return null;
}).then(() => {
    // will always get called when original promise resolves or rejects
    // somewhat like your .always
});

或者,您可以包装异步函数以返回所需的Promise类型:

function wrapFunc(arg) {
    return Parse.Promise.resolve(someAsyncFunc(arg))
}

然后,改为调用包装器函数。


我不确定我是否建议这样做,因为您正在修改可能会影响其他代码的可全局访问的Promise原型,但是您也可以在内置的Promise中添加.always()

Promise.prototype.always = function(fn) {
    return this.then(fn, fn);
}

实际上是完全相同的实现that Parse uses。然后,您可以对.always()函数返回的承诺使用async

答案 1 :(得分:0)

jfriend00的答案是可以接受的解决方案。 .catch(value => {return value}).then(...)基本上将充当.always()

就我而言,我不想这样做,因为这意味着我在许多地方打补丁以解决源于一个的问题。我正在重做一个使用Parse.Promise来使用async / await的现有函数,并且我还为其添加了一些功能。在完成之前,我没有发现.always()问题。我不想简单地放弃返工并用诺言再次重做更新。

虽然草率,但我最终将自己的辅助函数包装在了自己的辅助函数中。原始的助手功能是 not 异步的,并基于异步helper-helper函数的结果返回已解决的promise。

const promiseErrorTestHelper = async (<same params>) => {
    let returnPromise = new Parse.Promise();

    promiseErrorTestHelperHelper(<same params>).then(
        success => { returnPromise.resolve(success); },
        error => { returnPromise.reject(error); }
    );

    return returnPromise;
}

const promiseErrorTestHelperHelper = async () => {
    // This can return whatever, body and parameters
    // copied in entirety from parent function
}

Parse.Cloud.define('promiseErrorTest', async(req, res) => {
    promiseErrorTestHelper().then(
        res.success
    );
});

这使我能够像以前一样调用原始的辅助函数,尽管实现已更新为更简洁,更易读。

但是,有一件事是我不能使用函数式编程,这是我最近一直在学习并试图付诸实践的。这不起作用:

const promiseErrorTestHelper = async (<same params>) => {
    let returnPromise = new Parse.Promise();

    promiseErrorTestHelperHelper(<same params>).then(
        returnPromise.resolve,
        returnPromise.reject
    );

    return returnPromise;
}

我的理解是,这实际上应该与上面的相同,只是没有被包裹在匿名函数中。当然,该变量没有命名,但是应该以任何一种方式传递给这些方法,对吗?我在其他地方使用了这种模式,尽管不是为了promise.resolve /拒绝,因为我直接将其返回。但是我对我的云函数有很多.then( response.success, response.error )的调用,而不是像上面的工作示例那样将returnPromise.resolve交换为response.success,而将returnPromise.reject交换为{{ 1}}。那些工作正常。