sisterAn / JavaScript-Algorithms

基础理论+JS框架应用+实践,从0到1构建整个前端算法体系

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

sisterAn opened this issue · comments

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()

1s 后同时打印 1、4、9

原因:使用 promiseasync 函数作为 forEach() 等类似方法的 callback 参数并不会等待异步的执行

如果我们希望每隔 1s 输出一个结果,方法有:

  • 一个简单的 for 循环
  • for…of / for…in 循环
  • 利用 promise 的链式调用

解法一:for 循环

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

解法二:for…in / for…of

for...in

async function test() {
    for(let i in list) {
        const res = await square(list[i])
    	console.log(res)
    }
}
test()

for...of

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

解法三:利用 promise 的链式调用

function test() {
    let promise = Promise.resolve()
    list.forEach(x=> {
        promise = promise.then(() => square(x)).then(console.log)
    })
}
test()

运行结果:一秒后输出1,4,9

原因:在forEach里面写的callback函数会直接在while循环里面调用

改造:用for...of 或者for循环代替 forEach

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

贴一下forEach的源码

if (!Array.prototype.forEach) {
  Array.prototype.forEach = function(callback, thisArg) {
    var T, k;
    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }

    var O = Object(this);
    var len = O.length >>> 0;

    if (typeof callback !== "function") {
      throw new TypeError(callback + ' is not a function');
    }

    if (arguments.length > 1) {
      T = thisArg;
    }
    k = 0;

    while (k < len) {
      var kValue;
      if (k in O) {
        kValue = O[k];
        callback.call(T, kValue, k, O);
      }
      k++;
    }
  };
}
commented

运行结果,直接输出1 4 9
原因:是同步代码,直接执行了
代码:

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

遍历异步的循环

运行结果,直接输出1 4 9
原因:用了递归调用
代码:

const list = [1, 2, 3]
const square = num => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(num * num)
        }, 1000)
    })
}
async function test(index = 0) {
    const res = await square(list[index])
    console.log(res)
    if (list[++index]) {
        test(index)
    }
}
test()
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();

function test2() {
  let p = Promise.resolve();
  for (const item of list) {
    p = p.then(() => square(item).then(console.log));
  }
}
test2();

async function test3() {
  for (const item of list) {
    const res = await square(item);
    console.log(res);
  }
}
test3();

function test4() {
  class Schedule {
    constructor() {
      this.list = [];
      this.status = "waiting";
    }
    add(fn) {
      this.list.push(fn);
      if (this.status === "waiting") {
        this.run();
      }
    }
    async run() {
      this.status = "running";
      while (this.list.length) {
        const task = this.list.shift();
        await task();
      }
      this.status = "waiting";
    }
  }
  const schedule = new Schedule();
  for (const item of list) {
    schedule.add(() => square(item).then(console.log));
  }
}
test4();