IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    答案是丰富多彩的5::js实现循环setTimeout输出0,1,2,3,4

    zongyan86发表于 2017-04-25 06:58:19
    love 0

    这是js比较常见的一个题目:

    for (var i = 0; i < 5; i++) {
        setTimeout(function() {
            console.log(new Date, i);
        }, 1000);
    }

    结果为:

    Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5
    Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5
    Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5
    Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5
    Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5

    而不是我们所期望的

    Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 0
    VM595:4 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 1
    VM595:4 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 2
    VM595:4 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 3
    VM595:4 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 4

    解决方法:

    第一种:闭包

    for (var i = 0; i < 5; i++) {
        (function(j) {  // j = i
            setTimeout(function() {
                console.log(new Date, j);
            }, 1000);
        })(i);
    }

    第二种:值类型传递

    var output = function (i) {
        setTimeout(function() {
            console.log(new Date, i);
        }, 1000);
    };
    
    for (var i = 0; i < 5; i++) {
        output(i);  // 这里传过去的 i 值被复制了
    }
    
    console.log(new Date, i);

    第三种:es6 let

    for (let i = 0; i < 5; i++) {
        setTimeout(function() {
            console.log(new Date, i);
        }, 1000);
    }

    那如果要让0-4一秒一秒地输出来呢?

    第一种:

    for (var i = 0; i < 5; i++) {
        (function(j) {
            setTimeout(function() {
                console.log(new Date, j);
            }, 1000 * j);  // 这里修改 0~4 的定时器时间
        })(i);
    }
    
    setTimeout(function() { // 这里增加定时器,超时设置为 5 秒
        console.log(new Date, i);
    }, 1000 * i);

    第二种:

    const tasks = [];
    for (var i = 0; i < 5; i++) {   // 这里 i 的声明不能改成 let,如果要改该怎么做?
        ((j) => {
            tasks.push(new Promise((resolve) => {
                setTimeout(() => {
                    console.log(new Date, j);
                    resolve();  // 这里一定要 resolve,否则代码不会按预期 work
                }, 1000 * j);   // 定时器的超时时间逐步增加
            }));
        })(i);
    }
    
    Promise.all(tasks).then(() => {
        setTimeout(() => {
            console.log(new Date, i);
        }, 1000);   // 注意这里只需要把超时设置为 1 秒
    });

    第三种:

    const tasks = []; // 这里存放异步操作的 Promise
    const output = (i) => new Promise((resolve) => {
        setTimeout(() => {
            console.log(new Date, i);
            resolve();
        }, 1000 * i);
    });
    
    // 生成全部的异步操作
    for (var i = 0; i < 5; i++) {
        tasks.push(output(i));
    }
    
    // 异步操作完成之后,输出最后的 i
    Promise.all(tasks).then(() => {
        setTimeout(() => {
            console.log(new Date, i);
        }, 1000);
    });

    第四种:

    // 模拟其他语言中的 sleep,实际上可以是任何异步操作
    const sleep = (timeountMS) => new Promise((resolve) => {
        setTimeout(resolve, timeountMS);
    });
    
    (async () => {  // 声明即执行的 async 函数表达式
        for (var i = 0; i < 5; i++) {
            await sleep(1000);
            console.log(new Date, i);
        }
    
        await sleep(1000);
        console.log(new Date, i);
    })();
    

    web开发分享

    您可能也喜欢:
    答案是丰富多彩的4:js实现斐波那契数列
    js继承
    vue系列教程:2.vue.js的第一个demo
    js基本类型和引用类型
    vue系列教程:1.为啥选择vue.js?
    无觅

    声明: 本文采用 BY-NC-SA 协议进行授权 | WEB开发分享
    转载请注明转自《答案是丰富多彩的5::js实现循环setTimeout输出0,1,2,3,4》



沪ICP备19023445号-2号
友情链接