尝试与 JS API 交互,但在由 Grunt 任务运行时失败;我觉得我的逻辑很困惑。我的步骤:
- 从文件中获取 token ,检查它们 (
check_tokens
) - 如果它们是旧的 - 刷新它们(
refresh_tokens
) - 调用 API 刷新,如果失败 - 获取新的 (
authorize_with_api
) <- 这就是问题所在 - 来自
authorize_with_api
错误拒绝或使用 token 解决
目前 Grunt 任务报告一个 UnhandledPromiseRejectionWarning
并且永远不会完成。如果我注释掉对 authorize_with_api
的调用,它会正确退出并出现错误,并且我会打印最上面的 caught error!
消息。
为什么我不能从执行函数中返回一个 promise ?我的逻辑有什么问题?
/* global sdk, config, tokens */
return getTokens().then((p_tokens) => {
tokens = p_tokens;
return check_tokens(tokens);
}).then((tokens) => {
console.log('then() is called!');
}).catch((err) => {
console.error('caught error!', err);
});
function check_tokens(tokens) {
if(are_old(tokens)) { // returns true
return refresh_tokens(tokens);
}
return Promise.resolve(tokens);
}
function refresh_tokens(tokens) {
return new Promise(function(resolve, reject) {
sdk.refreshTokens(tokens.refresh_token, function(err, new_tokens) {
if(err) {
if(error.code === 'invalid_grant') {
return authorize_with_api();
}
reject('refreshTokens failed');
} else if(newTokens) {
resolve(new_tokens);
}
});
});
}
function authorize_with_api() {
return new Promise(function(resolve, reject) {
sdk.getTokens(config.auth_code, function(err, tokens) {
if(err) {
reject('getTokens failed');
} else if(tokens) {
resolve(tokens);
}
});
});
}
最佳答案
从 Promise 构造函数(或其中的任何函数)返回并不会解析 promise:
return new Promise(function(resolve, reject) {
sdk.refreshTokens(..., function(err, new_tokens) {
if(error.code === 'invalid_grant') {
return authorize_with_api();
} // ^--- this will not chain to the promise being created.
即使您没有从 sdk.refreshTokens
回调中返回,而是直接使用没有回调的 return authorize_with_api()
,结果仍然不会被束缚。
要解决 promise ,您不能从其构造函数返回,而必须显式调用给定回调之一(解决/拒绝):
return new Promise(function(resolve, reject) {
sdk.refreshTokens(..., function(err, new_tokens) {
if(error.code === 'invalid_grant') {
resolve(authorize_with_api());
} // ^--- must call resolve here
解决 promise 实际上也会处理拒绝,因此无论 authorize_with_api
是解决还是拒绝,状态都会相应地向上传播。
我的建议是仍然保留 return
语句,以维持 if
分支的预期视觉语义,条件是提前返回,但代码在没有它的情况下也能工作,因为 Promises can only be resolved once 和所有对 reject
/resolve
的进一步调用都将被忽略。
return new Promise(function(resolve, reject) {
sdk.refreshTokens(..., function(err, new_tokens) {
if(error.code === 'invalid_grant') {
return resolve(authorize_with_api());
} // ^--- should still return here for readability - clean logic purposes
reject('refreshTokens failed'); // this will be ignored if the above `resolve` gets called first, no matter if you have the `return` statement
例子:
function success() {
return Promise.resolve('success');
}
function error() {
return Promise.reject('error');
}
function alwaysPending() {
return new Promise(() => {
return success();
});
}
function resolves() {
return new Promise((resolve) => {
resolve(success());
});
}
function rejects() {
return new Promise((resolve) => {
resolve(error());
});
}
alwaysPending().then(console.log); // doesn't log anything
resolves().then(console.log);
rejects().catch(console.log);
关于javascript - 从执行函数返回 promise ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41488363/