第 160 题:输出以下代码运行结果,为什么?如果希望每隔 1s 输出一个结果,应该如何改造?注意不可改动 square 方法

发布于 2022-11-25 20:19:54 字数 309 浏览 97 评论 24

const list = [1, 2, 3]
const square = num => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(num * num)
    }, 1000)
  })
}

function test() {
  list.forEach(async x=> {
    const res = await square(x)
    console.log(res)
  })
}
test()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(24

那一片橙海, 2022-05-04 13:54:11
const list = [1, 2, 3]
const square = num => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(num * num)
        }, 1000)
    })
}

function test() {
    list.forEach(x=> {
        setTimeout(async x => {
            const res = await square(x)
            console.log(res)
        }, x*1000, x)
    })
}
test()
过期以后 2022-05-04 13:54:11
function test() {
 list.reduce(
   (pre, cur) => pre.then(() => square(cur)).then(console.log),
   Promise.resolve()
 );
}

test();
牵强ㄟ 2022-05-04 13:54:11
// 解法一,for循环

async function test() {
  for (let i = 0, len = list.length; i < len; i++) {
    const res = await square(list[i])
    console.log(res)
  }
}
// 解法2 for of循环
async function test() {
  for (x of list) {
    const res = await square(x)
    console.log(res)
  }
}
// 解法3 类似koa里面的compose思想解决
async function test() {
  const compose = (middleware, next) => {
    let index = -1
    return (ctx) => {
      const dispatch = (i) => {
        if (index < i ) {
          index = i
        }
        let fn = middleware[ index ]

        if (index === middleware.length) {
          fn = next
        }

        if (!fn) {
          return Promise.resolve()
        }

        return Promise.resolve(fn(ctx, async () => {
          return dispatch(index + 1)
        }))
      }

      dispatch(0)
    }
  }
  
  const middleware = []
  list.forEach((it) => {
    middleware.push(async (ctx, next) => {
      const res = await square(it)
      console.log(res)
      await next()
    })
  })

  compose(middleware, () => {
    console.log('end')
  })({ name: 'qianlongo' })
}

// 解法4 next思想 也是koa1的中间件执行思想

async function test() {
  let middleware = []

  list.forEach((it) =>{
    middleware.push(async (cb) => {
      const res = await square(it)
      console.log(res)
      cb && cb()
    })
  })
  
  const bindNext = (cbs) => {
    let next = function () {
      console.log('111')
    }
    let len = cbs.length

    while (len--) {
      next = cbs[ len ].bind(null, next)
    }

    return next
  }

  bindNext(middleware)()
}

// 解法5 利用promise的链式调用
function test() {
  let promise = Promise.resolve()

  list.forEach(x => {
    promise = promise.then(() => square(x)).then((res) => {
      console.log(res)
    })
  })
}


test()
花落人断肠 2022-05-04 13:54:11

题目本身有些问题,定时功能实现 square 中需要进行误差修正的

吲‖鸣 2022-05-04 13:54:11

forEach的回调是一个个单独的函数,跟其他回调同时执行

精品

顾忌 2022-05-04 13:54:11

《ES6 入门》中还提到了使用 reduce 解决:

list.reduce(async (_, x) => {
  await _
  const res = await square(x)
  console.log(res)
}, undefined)

大哥 这里面都没有return 为什么await _ (_) 会是上一次的方法呢 怎么累积的呢 ???
传统的 不都是这样的吗
var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
return accumulator + currentValue;
}, 0);
能帮忙解答下吗 迷茫。。。。。

小帐篷〃 2022-05-04 13:54:11

forEach是不能阻塞的,默认是请求并行发起,所以是同时输出1、4、9。

串行解决方案:

async function test() {
  for (let i = 0; i < list.length; i++) {
    let x = list[i]
    const res = await square(x)
    console.log(res)
  }
}

当然,也可以用 for of 语法,就是帅:

async function test() {
  for (let x of list) {
    const res = await square(x)
    console.log(res)
  }
}

还有一个更硬核点的,也是 axios 源码里所用到的,利用 promise 本身的链式调用来实现串行。

let promise = Promise.resolve()
function test(i = 0) {
  if (i === list.length) return
  promise = promise.then(() => square(list[i]))
  test(i + 1)
}
test()

promise的实现根本没有输出呢

猥︴琐丶欲为 2022-05-04 13:54:11

《ES6 入门》中还提到了使用 reduce 解决:

list.reduce(async (_, x) => {
  await _
  const res = await square(x)
  console.log(res)
}, undefined)

大哥 这里面都没有return 为什么await _ (_) 会是上一次的方法呢 怎么累积的呢 ???
传统的 不都是这样的吗
var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
return accumulator + currentValue;
}, 0);
能帮忙解答下吗 迷茫。。。。。

因为async函数的返回值是 Promise 对象

const asyncFunc = async () => {}
console.log(asyncFunc()) // Promise {<resolved>: undefined}
月隐月明月朦胧° 2022-05-04 13:54:11

一道题可以导出好多知识点,受教了各位大佬

如日中天 2022-05-04 13:54:11
const list = [1, 2, 3]
const square = num => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(num * num)
    }, 1000)
  })
}
//迭代器实现
async function test () {
  var iter = list[Symbol.iterator]();
  var flag = iter.next();
  while (!flag.done) {
    await square(flag.value).then(res => console.log(res));
    flag = iter.next();
  }
}
test();
哆啦不做梦 2022-05-04 13:54:11

forEach大概可以这么理解

Array.prototype.forEach = function (callback) {
  // this represents our array
  for (let index = 0; index < this.length; index++) {
    // We call the callback for each entry
    callback(this[index], index, this)
  }
}

所以是1秒后输出1, 4, 9; 几乎同时;但是有调用先后顺序;
改进的话, 大家都答了, 我就不嫌丑了...

度的依靠╰つ 2022-05-04 13:54:11

我以为我会,我答出来了,过来一看,我还是太年轻了

白云不回头 2022-05-04 13:54:09
const list = [1, 2, 3]
const square = num => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(num * num)
    }, 1000)
  })
}
function test() {
  ;(async () => {
    for await (let num of list) {
      const res = await square(num)
      console.log(res)
    }
  })()
}
test()
东走西顾 2022-05-04 13:54:03

《ES6 入门》里面是这样介绍的:
reduce 方法的第一个参数是 async 函数,导致该函数的第一个参数是前一步操作返回的 Promise 对象,所以必须使用await等待它操作结束

如果没有 await _ 这一行,得到的结果和 forEach() 是一样的,可以理解为 @linsicong003 所说的:源码里用 while 来一次性执行了所有回调

添加一行打印:

function test() {
  list.reduce(async (_, x) => {
    console.log(_, x) // 打印
    await _
    const res = await square(x)
    console.log(res)
  }, undefined)
}

test()

打印结果:

马上打印:
undefined 1
Promise { <pending> } 2
Promise { <pending> } 3

每隔一秒打印:
1
4
9
画▽骨i` 2022-05-04 13:54:03

为什么大厂面试的题都这么蹊跷???

瑶笙 2022-05-04 13:53:54

《ES6 入门》中还提到了使用 reduce 解决:

list.reduce(async (_, x) => {
  await _
  const res = await square(x)
  console.log(res)
}, undefined)

await _ 这个怎么理解呀 大哥

乖不如嘢 2022-05-04 13:50:28

直接在forEach 里面套个setTimeOut 不就可以了

function test() {
list.forEach(async x => {
setTimeout(async () => {
const res = await square(x)
console.log(res)
}, 1000 * x)
})
}

吾家有女初长成 2022-05-04 12:44:39

《ES6 入门》中还提到了使用 reduce 解决:

list.reduce(async (_, x) => {
  await _
  const res = await square(x)
  console.log(res)
}, undefined)
哑° 2022-05-04 12:39:40

@sl1673495 窃以为您的第三个串行方案的第四行代码后面应该加上.then(res => console.log(res))

季末如歌 2022-05-04 11:42:20

一秒后同时输出 1、4、9

如果要每隔一秒输出把 forEach 换成普通 for 循环或者 for...of... 循环即可

这里并行进行是因为 forEach 实现的问题,源码里用 while 来一次性执行了所有回调

具体参考官网 polyfill: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

你这个用 while 来一次性执行了所有回调描述不太准确吧,普通的for 等于同一个块作用域连续await,而forEach的回调是一个个单独的函数,跟其他回调同时执行,互不干扰

function test() {
    list.forEach(async x=> {
      const res = await square(x)
      console.log(res)
    })

    //forEach循环等于三个匿名函数;
    (async (x) => {
        const res = await square(x)
        console.log(res)
    })(1);
    (async (x) => {
        const res = await square(x)
        console.log(res)
    })(2);
    (async (x) => {
        const res = await square(x)
        console.log(res)
    })(3);

    // 上面的任务是同时进行
  }

  async function test() {
    for (let x of list) {
      const res = await square(x)
      console.log(res)
    }
  }
  //等价于

  async function test() {
      const res = await square(1)
      console.log(res)
      const res2 = await square(2)
      console.log(res)
      const res3 = await square(3)
      console.log(res)
  }
萌化 2022-05-04 06:49:32
async function test() {
  var n = list.length;

    while(n--) {
        const res = await s(list[n]);
        console.log(res);
    }
}
每隔一秒输出 9 4 1
滿滿的愛 2022-05-04 04:37:23

forEach是不能阻塞的,默认是请求并行发起,所以是同时输出1、2、3。

串行解决方案:

async function test() {
  for (let i = 0; i < list.length; i++) {
    let x = list[i]
    const res = await square(x)
    console.log(res)
  }
}

同时输出的是 1、2、3 的平方也就是 1 、4、9

不再让梦枯萎 2022-05-04 01:52:48

一秒后同时输出 1、4、9

如果要每隔一秒输出把 forEach 换成普通 for 循环或者 for...of... 循环即可

这里并行进行是因为 forEach 实现的问题,源码里用 while 来一次性执行了所有回调

具体参考官网 polyfill: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

两相知 2022-05-01 00:52:49

forEach是不能阻塞的,默认是请求并行发起,所以是同时输出1、4、9。

串行解决方案:

async function test() {
  for (let i = 0; i < list.length; i++) {
    let x = list[i]
    const res = await square(x)
    console.log(res)
  }
}

当然,也可以用 for of 语法,就是帅:

async function test() {
  for (let x of list) {
    const res = await square(x)
    console.log(res)
  }
}

还有一个更硬核点的,也是 axios 源码里所用到的,利用 promise 本身的链式调用来实现串行。

let promise = Promise.resolve()
function test(i = 0) {
  if (i === list.length) return
  promise = promise.then(() => square(list[i]))
  test(i + 1)
}
test()
~没有更多了~

关于作者

0 文章
0 评论
24 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文