-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 160 题:输出以下代码运行结果,为什么?如果希望每隔 1s 输出一个结果,应该如何改造?注意不可改动 square 方法 #389
Comments
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)
}
} 当然,也可以用 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() |
一秒后同时输出 1、4、9 如果要每隔一秒输出把 forEach 换成普通 for 循环或者 for...of... 循环即可 这里并行进行是因为 forEach 实现的问题,源码里用 while 来一次性执行了所有回调 具体参考官网 polyfill: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach |
同时输出的是 1、2、3 的平方也就是 1 、4、9 |
async function test() {
var n = list.length;
while(n--) {
const res = await s(list[n]);
console.log(res);
}
}
每隔一秒输出 9 4 1 |
你这个用 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)
} |
@sl1673495 窃以为您的第三个串行方案的第四行代码后面应该加上.then(res => console.log(res)) |
《ES6 入门》中还提到了使用 reduce 解决: list.reduce(async (_, x) => {
await _
const res = await square(x)
console.log(res)
}, undefined) |
直接在forEach 里面套个setTimeOut 不就可以了 function test() { |
await _ 这个怎么理解呀 大哥 |
《ES6 入门》里面是这样介绍的: 如果没有 添加一行打印: function test() {
list.reduce(async (_, x) => {
console.log(_, x) // 打印
await _
const res = await square(x)
console.log(res)
}, undefined)
}
test() 打印结果:
|
为什么大厂面试的题都这么蹊跷??? |
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() |
|
function test() {
list.reduce(
(pre, cur) => pre.then(() => square(cur)).then(console.log),
Promise.resolve()
);
}
test(); |
// 解法一,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() |
题目本身有些问题,定时功能实现 square 中需要进行误差修正的 |
精品 |
大哥 这里面都没有return 为什么await _ (_) 会是上一次的方法呢 怎么累积的呢 ??? |
promise的实现根本没有输出呢 |
因为async函数的返回值是 Promise 对象
|
一道题可以导出好多知识点,受教了各位大佬 |
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(); |
forEach大概可以这么理解
所以是1秒后输出1, 4, 9; 几乎同时;但是有调用先后顺序; |
我以为我会,我答出来了,过来一看,我还是太年轻了😅你们都是大佬 |
const list = [1, 2, 3];
const square = num => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
async function test() {
for (let x of list) {
const res = await square(x)
console.log(res)
}
}
test() |
|
const list = [1, 2, 3]; const square = async (num) => { const test = async () => { test(); |
以前面试遇到一个差不多的题,当时用的是链式递归实现的: function test(i = 0) {
if (i === list.length) return
return square(list[i]).then(res => {
console.log(res);
return test(++i)
})
}
test() |
对于forEach的并行处理,可以用下面这段代码来学习一下: const count = (item) => {
return new Promise((resolve) => {
if (typeof item === 'number') {
setTimeout(() => {
console.log(item);
resolve();
}, 500);
} else {
setTimeout(() => {
console.log(item);
resolve();
}, 1000);
}
})
}
// forEach
let arr = [1, 'a', 'b', 'c', 2];
arr.forEach(async item => {
const ret = await count(item);
});
// 1
// 2
// a
// b
// c
// for
(async function test() {
for (let i = 0; i < arr.length; i++) {
await count(arr[i]);
}
})()
// for ... of
(async function test() {
for (let x of arr) {
const res = await count(x)
}
})() |
const list = [1, 2, 3]
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
function test(i=0) {
console.log('i', i)
square(list[i]).then(num=>{
console.log(num)
if(list[i+1]){
test(i+1)
}
})
}
test() |
const list = [1, 2, 3]
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
(async function test() {
for (let x of list) {
const res = await square(x);
console.log(res);
}
})() |
const list = [1, 2, 3]
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
function test() {
test.p = Promise.resolve();
list.forEach(x => {
test.p = test.p.then(() => square(x)).then(console.log)
})
}
test() |
const list = [1, 2, 3]
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
function test() {
let promise = Promise.resolve();
list.forEach(x => {
promise = promise.then(() => square(x)).then(res => console.log(res))
})
}
test() |
第三种方式是有缺陷的,1秒后同时输出1,4,9 |
这角度相当刁钻了,就是但凡数组不是连续整数这代码还得改。。。应该用index去乘。 |
|
|
function test() {
list.reduce(async (p, x)=> {
await p;
const res = await square(x)
console.log(res, +new Date() / 1000)
}, Promise.resolve())
} |
`const list = [1, 2, 3] function test() { |
改造test就好了 function test() {
list.forEach(async(x, index)=> {
const res = await square(x)
setTimeout(() => {console.log(res)}, 1000*index)
})
} |
用reduce实现链式调用 const list = [1, 2, 3]
const square = num=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(num * num)
}
, 1000)
}
)
}
function test() {
list.reduce((p,x)=>{
return p.then(async()=>{
const res = await square(x)
console.log(res)
}
)
}
, Promise.resolve())
}
test() |
Hi~思聪已经收到你的邮件咯~待会就回复哦
|
重写 forEach Array.prototype.forEach = async function(callback, thisArg) {
let bindThis, idx;
if (this === null) {
throw new TypeError('this is null or not defined');
}
let arrayObj = Object(this);
let len = O.length >>> 0;
if (typeof callback !== 'function') {
throw new TypeError(callback + 'is not a function')
}
if (arguments.length > 1) {
bindThis = thisArg;
}
idx = 0
while (idx < len) {
let item;
if (idx in arrayObj) {
item = arrayObj[idx];
await callback.call(bindThis, item, idx, arrayObj);
}
idx++;
}
}
arr = new Array(1,2,3);
async function foo(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(n + n);
}, 1000);
});
}
arr.forEach(async (item) => {
console.log(await foo(item));
}); |
Hi~思聪已经收到你的邮件咯~待会就回复哦
|
const list = [1, 2, 3];
const square = (num) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num);
}, 1000);
});
};
async function test() {
for (const item of list) {
const res = await square(item);
console.log(res);
}
}
test(); |
for reduce function test() {
list.reduce((acc,cur,index)=> acc.then(()=>square(list[index])),Promise.resolve());
}
|
Hi~思聪已经收到你的邮件咯~待会就回复哦
|
const list = [1, 2, 3];
const square = (num) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num);
}, 1000);
});
};
async function test(index) {
const val = list[index];
if (val === undefined) return;
const res = await square(val);
console.log(res);
test(index + 1);
}
test(0); |
const list = [1, 2, 3]
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
function test() {
list.forEach(async (x, i)=> {
const res = await square(x)
setTimeout(() => console.log(res), i * 1000)
})
}
test() |
Hi~思聪已经收到你的邮件咯~待会就回复哦
|
list.reduce((_, x) => { console.log(_, x) }, undefined) 中 [3, 2, 1].reduce((_, x) => { console.log(_, x); return `init${x}`; }, 'init') 结果为 init 3
init3 2
init2 1 当加入 async function firstCb(_, x) {
await undefined;
const res = await square(x);
console.log(res);
}
firstCb(undefined, 1); 第二次回调执行可以看作是 async function secondCb(_, x) {
await _;
const res = await square(x);
console.log(res);
}
secondCb(firstCb(), 2); 在执行 |
Hi~思聪已经收到你的邮件咯~待会就回复哦
|
1 similar comment
Hi~思聪已经收到你的邮件咯~待会就回复哦
|
1秒后同时输出 1, 4, 9。因为forEach方法传入的函数是通过内部的循环去执行,将它写为async函数并不能阻塞循环。想要理解问题的关键点,首先要知道forEach是如何实现的。 forEach的简单实现 Array.prototype.forEach = function (fun) {
for (let i = 0; i < this.length; i++) {
fun.call(this, this[i], i, this); // 此时fun为async函数
}
} 改造test: async function test() {
for(let x of list) {
const res = await square(x)
console.log(res)
}
}
test() |
The text was updated successfully, but these errors were encountered: