我需要修改现有代码以支持同步和异步结果。尽管我可以轻松地在C#中处理Task
和await
,但是即使从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。
答案 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