承诺并修改返回值

时间:2019-03-17 20:48:05

标签: javascript promise

我需要修改现有代码以支持同步和异步结果。尽管我可以轻松地在C#中处理Taskawait,但是即使从MDN和其他页面上读取了很多内容,我仍然无法理解JavaScript Promise

现有代码如下:

function dispatchCall() {
    // ...

    try {
        let result = fn.apply(context, args);

        if (result !== undefined) {
            return { status: 0, result: result };
        }
        return { status: 0 };
    }
    catch (err) {
        if (typeof err === "object") {
            return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack };
        }
        return { status: 400, errorMessage: err };
    }
}

fn是要调用的函数。它是由我的API的用户定义的,所以我不知道它会做什么。现在,它将始终返回值或引发异常。该值将被包装在一个消息对象中,该消息对象将被传递回dispatchCall的远程调用方。

现在fn需要返回一个Promise,因为它将用于异步工作流中,在该异步工作流中无法立即获得结果。

我需要测试result是否为Promise(或“ thenable”)并采取相应措施。在这种情况下,当解决了结果承诺时,我需要将结果值包装在适当的消息对象中,并将其作为另一个承诺传递给dispatchCall的调用方。然后我可以在那里轻松地处理它。

这是我无法解决的“传递和修改值”。

这是我开始做事的方式:

function dispatchCall() {
    // ...

    try {
        let result = fn.apply(context, args);

        // --------------------------------------------------
        if (result && typeof result.then === "function") {
            result.then(function (result) {
                // Like so?
                if (result !== undefined) {
                    return { status: 0, result: result };
                }
                return { status: 0 };
            })
            .catch(function (err) {
                // Does this catch errors?
                if (typeof err === "object") {
                    return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack };
                }
                return { status: 400, errorMessage: err };
            });
            return new Promise(function(resolve, reject) {
                // What about this?
                // When should I call resolve and reject and with what arguments?
            });
            // Must return a Promise and not continue at this point!
        }
        // --------------------------------------------------

        if (result !== undefined) {
            return { status: 0, result: result };
        }
        return { status: 0 };
    }
    catch (err) {
        if (typeof err === "object") {
            return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack };
        }
        return { status: 400, errorMessage: err };
    }
}

应该如何将它们粘在一起?

查看支持表后,我决定放弃Internet Explorer的支持并使用ES6 Promises。不涉及外部库。如果某些IE会执行此操作,则它应继续使用同步功能,并因异步代码而惨遭失败。

我的目标环境是浏览器和Node.js。

3 个答案:

答案 0 :(得分:2)

当您有一个大礼包时,不需要与const context = require.context('.', true, /^\.\/(?!index\.js).*\.js$/, 'sync'); let resolvers = []; context.keys().forEach(module => { resolvers.push(context(module).default) }); export default resolvers 一起创建诺言。

您可以只返回new Promise,或者如果您想确保返回Promise实例(不仅是return result.then(......返回的内容),然后将结果传递给:then().catch() < / p>

Promise.resolve()

如果 if (typeof result.then === "function") { return Promise.resolve(result).then(function (result) { if (result !== undefined) { return { status: 0, result: result }; } return { status: 0 }; }) .catch(function (err) { if (typeof err === "object") { return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack }; } return { status: 400, errorMessage: err }; }); } 回调中发生错误,则返回的承诺将被视为拒绝。调用者可以通过链接到它自己的catch来处理它。

答案 1 :(得分:1)

由于结果可能是异步检索的,因此dispatchCall 的使用者必须具有逻辑来等待可能异步的数据返回。一种选择是让dispatchCall返回一个Promise,该承诺最终会解析为您要寻找的{ status, result }对象(或{ status, error }对象):

if (typeof result.then === "function") {
  return result
    .then((resolveValue) => {
      return { status: 0, result: resolveValue };
    })
    .catch((error) => {
      return { status: 400, error };
    })
}

dispatchCall的使用者中,检查返回的值是否为Promise-如果是,则对其调用.then

const dispatchResult = dispatchCall();
if (typeof dispatchResult.then === 'function') {
  dispatchResult.then(({ status, result, error }) => {
    // do stuff with status, result, error here
    // if there was an error, result will be undefined
  });
} else {
  // do stuff with dispatchResult.status, .result, .errorMessage
}

您还可以考虑返回result是否为Promise的Promise ,以便使代码更易于管理-例如,在同步部分:< / p>

return Promise.resolve({ status: 0, result: result });

答案 2 :(得分:0)

fn()没有返回承诺时,您真的需要同步返回该对象吗?如果您的函数总是可以返回promise,那么 会容易得多。您只需用值resolve function dispatchCall() { // ... // return Promise.resolve(fn.apply(context, args))… - doesn't catch synchronous exceptions return new Promise(function(resolve) { resolve(fn.apply(context, args)); // promise constructor catches exceptions }).then(function (result) { // the promise was fulfilled if (result !== undefined) { return { status: 0, result: result }; } else { return { status: 0 }; } }, function (err) { // the promise was rejected if (typeof err === "object") { return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack }; } else { return { status: 400, errorMessage: err }; } }); } ,无论它是纯值,可续费还是承诺,您都可以从中得到承诺。

然后,将您的结果/错误处理逻辑链接到该链接一次,

rails g spree:install