async/await遇到map和reduce

map

首先我们来看看同步的map怎么写。

// 对数组所有元素乘2
[1,2,3].map(value => value * 2); // [2,4,6]
复制代码

那如果map函数需要进行异步操作才能返回结果应该怎么写呢?

[1, 2, 3].map(async value => value * 2); // [Promise, Promise, Promise]
复制代码

async函数执行完会返回Promise对象,map就直接接收后装进新数组了,数组内容直接变成了三个Promise,这显然不是我们想要的结果,所以我们要对Promise数组再进一步操作取出其中的值。

await Promise.all([1, 2, 3].map(async value => value * 2)) // [2,4,6]
复制代码

这里的Promise.all会将一个由Promise组成的数组依次执行,并返回一个Promise对象,该对象的结果为数组产生的结果集。

reduce

对于reduce来说,也是基本和map差不多的思路,只是需要提前将前一次的结果用await取出Prmose的值,再进行运算。

await [1, 2, 3].reduce(async(previousValue, currentValue) => await previousValue + currentValue, 0) // 6
复制代码

filter

感觉好简单啊,那数组的异步filter能不能也像map这么写呢?

await Promise.all([1, 2, 3].filter(async value => value % 2 === 1)) // [1,2,3]

复制代码

结果没对啊,async返回的Promise被直接判断成true,导致一个元素也没被过滤掉。

const filterResults = await Promise.all([1, 2, 3]
                            .map(async value => (value % 2 === 1))); // [true,false,true]
[1, 2, 3].filter((value, index) => filterResults[index]); // [1,3]
复制代码

这里我们使用了一个临时数组配合前面map先获取异步filter对应每个元素的结果,然后再使用filter过滤数组,搞定~

Promise库

刚开写asyncMap的时候,以为其他的方法也会这么简单,后来发现事情并没简单,只好找了个Promise库 bluebird,专门处理这些异步操作~~~

除了提供有常见的map、filter、reduce、some之外,还提供了PromisifyAll,直接把回调库Promise化。

var fs = require("fs");
Promise.promisifyAll(fs);
fs.readFileAsync("file.js", "utf8").then(...)
复制代码

也支持第三方库

var Promise = require("bluebird");
Promise.promisifyAll(require("redis"));

自测

附上一个async/await结合reduce的自测题

题目

// 要求实现asyncWrap函数,输出1+2+3的值
async function asyncAdd(a,b){
	return new Promise((resolve)=>{
		setTimeout(()=>{
			resolve(a+b)
		},500)
	})
}

asyncWrap(asyncAdd)([1,2,3]).then(data=>{
	console.log(data)
})

// 思路
asyncWrap()
asyncWrap(asyncAdd)([1,2,3])
asyncWrap(asyncAdd)
reduce

答案

async function asyncAdd(a, b) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(a + b)
    }, 500)
  })
}

function asyncWrap(fn) {
  return async arr => {
    return await arr.reduce(async (acc, value) => {
      let repromise = await acc
      return await fn(repromise, value)
    })
  }
}

asyncWrap(asyncAdd)([1, 2, 3]).then(data => {
  console.log(data)
})
上次更新: 3/10/2020, 11:33:44 PM