承诺并修改返回值

ygo*_*goe 5 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 };
    }
}
Run Code Online (Sandbox Code Playgroud)

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

现在fn需要返回 a,Promise因为它将在结果无法立即可用的异步工作流程中使用。

我需要测试是否result是 a 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 };
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该如何粘合在一起?

查看支持表后,我决定放弃 Internet Explorer 支持并使用 ES6 Promises。不涉及外部库。如果某些 IE 执行此操作,它应该继续使用同步函数,并允许在异步代码中严重失败。

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

tri*_*cot 5

new Promise当你有 thenable 时,不需要创建一个 Promise 。

您可以只 return return result.then(......,或者如果您想确保返回一个 Promise 实例(而不仅仅是then().catch()返回的任何内容),则将结果传递给: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 };
        });
    }
Run Code Online (Sandbox Code Playgroud)

如果回调中发生错误catch,则返回的 Promise 将解析为被拒绝。调用者可以用自己的catch链接来处理这个问题。


Cer*_*nce 2

由于结果可能会异步检索,因此使用者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 };
    })
}
Run Code Online (Sandbox Code Playgroud)

在 的消费者中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
}
Run Code Online (Sandbox Code Playgroud)

你也可以考虑不管是否result是 Promise 都返回一个 Promise,这样可以让代码更容易管理——例如在同步部分:

return Promise.resolve({ status: 0, result: result });
Run Code Online (Sandbox Code Playgroud)