通过使用 async/await

问题描述

代码中使用的变量和函数

const fakeAPI = (delay,value) =>
 new Promise(resolve => setTimeout(() => resolve(value),delay));

const useResult = x => console.log(new Date(),x);

代码通过使用 reduce() 实现来打印 forEach 不能通过异步调用实现的内容

const forEachAsync = (arr,fn) =>
 arr.reduce(
 (promise,value) => promise.then(() => fn(value)),Promise.resolve()
 );
(async () => {
 console.log("START FOREACH VIA REDUCE");
 await forEachAsync([1,2,3,4],async n => {
 const x = await fakeAPI(n * 1000,n);
 useResult(x);
 });
 console.log("END FOREACH VIA REDUCE");
})();

输出

/*
START FOREACH VIA REDUCE
2019-10-13T20:02:23.437Z 1
2019-10-13T20:02:24.446Z 2
2019-10-13T20:02:25.949Z 3
2019-10-13T20:02:27.952Z 4
END FOREACH VIA REDUCE
*/

代码块上下文中arr.reduce函数中promise和value参数的作用是什么?

value 参数是否传递给了 async n 箭头函数

尽管如此,我更喜欢解释,因为我正在研究功能程序,但是,如果有任何其他方式以 FP 方式处理此问题,我将不胜感激。

解决方法

forEach

forEach 是您正在研究的代码不好的副作用。该示例使用 asyncawait,因此使用 .reduce 链接 .then 调用是没有意义的。也就是说,如果你想体验它的使用痛苦,我们可以实现它 -

async function forEach (arr,fn)
{ for (const x of arr)
    await fn(x)         // <- return value of fn disappears
}

const sleep = ms =>
  new Promise(r => setTimeout(r,ms))

const fakeApi = x =>
  sleep(1000).then(_ => `api response: ${x * x}`)

forEach
  ( [1,2,3,4],async x =>
      // side effect tangled with task processing code
      console.log((new Date).toUTCString(),await fakeApi(x))
  )
  .then(console.log,console.error) // <- no values beyond this point

"Sat,30 Jan 2021 16:46:35 GMT" "api response: 1"   // <- :35
"Sat,30 Jan 2021 16:46:36 GMT" "api response: 4"   // <- :36
"Sat,30 Jan 2021 16:46:37 GMT" "api response: 9"   // <- :37
"Sat,30 Jan 2021 16:46:38 GMT" "api response: 16"  // <- :38
undefined

要解决上述问题,请注意 serialparallel(如下)如何将数据保存在 承诺中,而不是使用 {{ 1}} 或 console.log

串行

我们可以写useResult,它以串行顺序处理任务-

serial

async function serial (arr,fn)
{ let r = []
  for (const x of arr)
    r.push(await fn(x))
  return r
}

const sleep = ms =>
  new Promise(r => setTimeout(r,ms))

const fakeApi = x =>
  sleep(1000).then(_ => `api response: ${x * x}`)

serial
  ( [1,async x => [ (new Date).toUTCString(),await fakeApi(x) ]
  )
  .then(console.log,console.error)

平行

或者我们可以写[ [ "Sat,30 Jan 2021 16:39:04 GMT",// <- :04 "api response: 1" ],[ "Sat,30 Jan 2021 16:39:05 GMT",// <- :05 "api response: 4" ],30 Jan 2021 16:39:06 GMT",// <- :06 "api response: 9" ],30 Jan 2021 16:39:07 GMT",// <- :07 "api response: 16" ] ] ,它以并行-

处理任务

parallel

const parallel = (arr,fn) =>
  Promise.all(arr.map(v => fn(v)))

const sleep = ms =>
  new Promise(r => setTimeout(r,ms))

const fakeApi = x =>
  sleep(1000).then(_ => `api response: ${x * x}`)

parallel
  ( [1,console.error)