还是先前那个用户列表,我们希望找到没有电子邮件地址的人的用户名,返回它们用户名用逗号拼接的字符串。一种方法是使用两个单独的操作:
获取过滤无电子邮件后的条目
获取用户名并拼接
将它们放在一起可能看起来像这样:
function notEmptyEmail(x) { return !!x.email } function notEmptyEmailUsername(a, b) { return a ? `${a},${b.username}` : b.username } const userWithEmail = userList.filter(notEmptyEmail); const userWithEmailFormatStr = userWithEmail.reduce(notEmptyEmailUsername, ''); console.log(userWithEmailFormatStr); // 'john,jerry'
现在,这段代码是完全可读的,对于小的样本数据不会有性能问题,但是如果我们有一个庞大的数组呢?如果我们修改我们的reducer回调,那么我们可以一次完成所有事情:
function notEmptyEmail(x) { return !!x.email } function notEmptyEmailUsername(usernameAcc, person){ return (notEmptyEmail(person)) ? (usernameAcc ? `${usernameAcc},${person.username}` : `${person.username}`) : usernameAcc; } const userWithEmailFormatStr = userList.reduce(notEmptyEmailUsername, ''); console.log(userWithEmailFormatStr); // 'john,jerry'
在这个版本中,我们只遍历一次数组,一般建议使用filter和map的组合,除非发现性能问题,才推荐使用reduce去做优化。
按顺序运行异步函数
我们可以做的另一件事.reduce()是按顺序运行promises(而不是并行)。如果您对API请求有速率限制,或者您需要将每个prmise的结果传递到下一个promise,reduce可以帮助到你。
举一个例子,假设我们想要为userList数组中的每个人获取消息。
function fetchMessages(username) { return fetch(`https://example.com/api/messages/${username}`) .then(response => response.json()); } function getUsername(person) { return person.username; } async function chainedFetchMessages(p, username) { // In this function, p is a promise. We wait for it to finish, // then run fetchMessages(). const obj = await p; const data = await fetchMessages(username); return { ...obj, [username]: data}; } const msgObj = userList .map(getUsername) .reduce(chainedFetchMessages, Promise.resolve({})) .then(console.log); // {glestrade: [ … ], mholmes: [ … ], iadler: [ … ]}
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
请注意,在此我们传递Promise作为初始值Promise.resolve(),我们的第一个API调用将立即运行。
下面是不使用async语法糖的版本
function fetchMessages(username) { return fetch(`https://example.com/api/messages/${username}`) .then(response => response.json()); } function getUsername(person) { return person.username; } function chainedFetchMessages(p, username) { // In this function, p is a promise. We wait for it to finish, // then run fetchMessages(). return p.then((obj)=>{ return fetchMessages(username).then(data=>{ return { ...obj, [username]: data } }) }) } const msgObj = peopleArr .map(getUsername) .reduce(chainedFetchMessages, Promise.resolve({})) .then(console.log); // {glestrade: [ … ], mholmes: [ … ], iadler: [ … ]}