- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有以下两个函数,每个函数返回一个 Promise:
const getToken = () => {
return new Promise((resolve, reject) => {
fs.readFile('token.txt', (err, data) => {
if (err) { return reject(err) }
if (!tokenIsExpired(data.token)) {
return resolve(data.token)
} else {
return requestNewToken()
}
})
})
}
const requestNewToken = () => {
return new Promise((resolve, reject) => {
restClient.get(url, (data, res) => {
fs.writeFile('tokenfile.txt', data.token, err => {
resolve(data.token)
})
})
})
}
function1()
.then(value => {
console.log('taco')
})
.catch(err => {
console.log(err)
})
因此,function1
运行,并且(取决于某些条件),它有时会返回 function2
,它返回另一个 Promise。在此代码中,当调用 function2
时,console.log('taco')
永远不会运行。为什么是这样?我认为,如果您从 Promise 中返回 Promise,则嵌套 Promise 的解析值就是在顶层解析的值。
为了让这个工作正常进行,我必须这样做:
const getToken = () => {
return new Promise((resolve, reject) => {
if (!tokenIsExpired()) {
return resolve(getToken())
} else {
return requestNewToken ()
.then(value => {
resolve(value)
})
}
})
}
这可行,但似乎我做错了什么。似乎应该有一种更优雅的方式来处理/构建这个。
最佳答案
你是对的, promise 自动解包,但在这种情况下,你从 promise 构造函数内部返回,该构造函数被忽略,你需要调用 resolve
或 reject
而不是使用 return
。我认为这可能是您正在寻找的解决方案:
const function1 = () => {
return new Promise((resolve, reject) => {
if (someCondition) {
resolve('foobar')
} else {
resolve(function2());
}
})
}
在 Promise 构造函数中,您需要调用 resolve
或 reject
,这相当于使用 return
或 throw
来自 then
回调内部。
如果您发现这种区别令人困惑(我确实如此),您应该通过使用 Promise.resolve
开始一个新链来完全避免使用 Promise 构造函数,如下所示:
const function1 = () => {
return Promise.resolve().then(() => {
if (someCondition) {
return 'foobar';
} else {
return function2();
}
})
}
const function2 = () => {
return new Promise((resolve, reject) => {
resolve('hello world')
})
}
someCondition = false;
function1()
.then(value => {
console.log(value)
})
对于更新后的代码,我建议使用库来包装 API,而不是自己访问 Promise 构造函数。例如,使用bluebird的promisify :
const bluebird = require('bluebird');
const readFile = bluebird.promisify(fs.readFile);
const writeFile = bluebird.promisify(fs.writeFile);
const getUrl = bluebird.promisify(restClient.get, {multiArgs:true});
const getToken = () => {
return readFile('token.txt')
.then((data) => {
if(!tokenIsExpired(data.token)) {
return data.token;
} else {
return requestNewToken();
}
});
};
const requestNewToken = () => {
return getUrl(url)
.then(([data, res]) => {
return writeFile('tokenFile.txt', data.token)
.then(() => data.token);
});
};
我仍然忠实于您的源代码,但我会注意到,编写 data.token
以及稍后尝试读取 token
可能会出现错误。该文件中的 code> 属性。
为什么使用库而不是 Promise 构造函数?
tokenIsExpired
函数使用您的 Promise 构造函数代码抛出错误,则该错误将会丢失。您需要将所有内部回调代码包装在 try {} catch(e) {reject(e)}
中,这很麻烦而且很容易被忘记。关于javascript - 如何在 Promise 中压平 Promise?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44054467/
我是一名优秀的程序员,十分优秀!