首页 新闻 会员 周边

被js的setTimeout搞得头疼

0
悬赏园豆:10 [已解决问题] 解决于 2021-01-25 11:05

在学习javascript的Promise对象,教程的其中一个源码是用123顺序执行几步算法。

<!DOCTYPE html>

<html lang="en">



<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

 <title>Document</title>

</head>



<body>

    <div id="test-promise-log" style="border: solid 1px #ccc; padding: 1em; margin: 15px 0;">

        <p>Log:</p>

 </div>

</body>

 

    'use strict';

   var logging = document.getElementById('test-promise-log');
   while (logging.children.length > 1) {
       logging.removeChild(logging.children[logging.children.length - 1]);
  }

   function log(s) {
       var p = document.createElement('p');
       p.innerHTML = s;
       logging.appendChild(p);
  }
   // 0.5秒后返回input*input的计算结果:
   function multiply(input) {
       return new Promise(function (resolve, reject) {
           log('calculating ' + input + ' x ' + input + '...');
           setTimeout(resolve, 500, input * input);
      });
  }

   // 0.5秒后返回input+input的计算结果:
   function add(input) {
       return new Promise(function (resolve, reject) {
           log('calculating ' + input + ' + ' + input + '...');
           setTimeout(resolve, 500, input + input);
      });
  }

   var p = new Promise(function (resolve, reject) {
       log('start new Promise...');
       resolve(123);
  });

   p.then(multiply)
      .then(add)
      .then(multiply)
      .then(add)
      .then(function (result) {
           log('Got value: ' + result);
      });

打算自己写js代码和原来用promise的代码比照来理解Promise的原理,但是原来程序的效果中步骤是每隔0.5打印的,结果我就卡在了实现隔秒的打印的settimeout函数上,我几次尝试的结果发现所有步骤都是同时被输出在页面上的:

 

不管是试图给每个函数后面设置延时:

 'use strict'

 var logging = document.getElementById('test-promise-log');

 while (logging.children.length > 1) {

   logging.removeChild(logging.children[logging.children.length - 1]);

}



 function log(s) {

   var p = document.createElement('p');

   p.innerHTML = s;

   logging.appendChild(p);

}

 // 0.5秒后返回input*input的计算结果:

 function multiply(input) {

   log('calculating ' + input + ' x ' + input + '...')

   return input * input;

}



 // 0.5秒后返回input+input的计算结果:

 function add(input) {

   log('calculating ' + input + ' + ' + input + '...')

   return input + input;

}



 log("Start Calculating...");

 var resolve = 123;



 resolve = multiply(resolve);

 setTimeout(function(){

   console.log('等待0.5秒');//结果是这4个console.log()0.5秒后同时在页面输出

},5000);

 resolve = add(resolve);

 setTimeout(function(){

   console.log('等待0.5秒');

},500);

 resolve = multiply(resolve);

 setTimeout(function(){

   console.log('等待0.5秒');

},500);

 var result = add(resolve);

 setTimeout(function(){

   console.log('等待0.5秒');

},500);  

 log('Got value: ' + result);

 

 

    function sleep(setTime)
  {
       var curTime = Date.now();
       while( Date.now() - curTime < setTime)
      {

      }
  }

...

log("Start Calculating...");//步骤仍旧是同时被打印,而且网页加载花了很长时间
   var resolve = 123;

   resolve = multiply(resolve);
   sleep(500);  
   resolve = add(resolve);
   sleep(500);  
   resolve = multiply(resolve);
   sleep(500);  
   var result = add(resolve);
   sleep(500);  
   log('Got value: ' + result);

 

还是试图在每个函数打印步骤的语句后面加上延时:

 function multiply(input) {

    setTimeout(function(){
      log('calculating ' + input + ' x ' + input + '...');//步骤仍旧同时打印
    },500);
       
       return input * input;
  }

总之用了很多方法,都以失败告终;思考了一下自己是基于C语言顺序执行的逻辑来思考代码的,然而我对于setTimeout()的机制我一无所知

现求助目的如下:

1.实现无promise各个计算步骤的延时打印

2.推荐几个js异步编程和promise的练习题(注意是能动手代码练习的,不是教程解说)

另一种开始的主页 另一种开始 | 初学一级 | 园豆:119
提问于:2021-01-05 22:37
< >
分享
最佳答案
0

setTimeout 的机制是设定一个定时器任务,等有空的时候再来看看
无论设定多长时间,都要等有空了才会去看
也就是说就算定时器的时间已经到了,但是此时主线程没空,仍然不会去执行定时器任务
哪怕设定的时间是 0,也不会立即执行
并不是说定时器设定的多少时间就一定是那个时间一到就立刻执行
而是只有等到主线程有空的时候,再把那些到时间的定时器任务捞出来执行
要执行定时器任务有两个前提就是 有空时间到了
你第一种写法,每个定时器都是设定的0.5秒,所以0.5秒过后,主线程一旦有空,就同时全部依次执行,因为每个定时器的时间都已经到了
而你第二种写法在你 sleep 的时候,主线程是没有空的,无论经过多少时间,都不会去执行定时器任务,只有等你全部 sleep 执行完毕后有空了再回过头来看前面的定时器任务,发现都超过设定时间了,所以也是同时全部依次执行
我这么说,说明白了吗

收获园豆:10
by.Genesis | 老鸟四级 |园豆:2719 | 2021-01-06 09:31

学了有关宏微任务和任务队列概念大概懂了,不过设想是不用promise,单用set类函数做出顺序间隔执行效果,目前还是没有思路。

另一种开始 | 园豆:119 (初学一级) | 2021-01-06 21:08

@另一种开始: 在定时器回调函数里面设定下一个定时器

const foo = () => {
  console.log('foo')
  setTimeout(bar, 500)
}
const bar = () => {
  console.log('bar')
}
setTimeout(foo, 500)
by.Genesis | 园豆:2719 (老鸟四级) | 2021-01-07 09:25
其他回答(5)
0

碰巧看到一篇文章:https://segmentfault.com/a/1190000038829248

练涛 | 园豆:12 (初学一级) | 2021-01-06 09:13
0

setTimeout是异步执行的,如果你想要顺序间隔执行,可以使用setInterval,或者是在setTimeout执行的方法内部调用另一个方法(也就是方法执行完后再执行下面一个方法),而不是再外部调用多个setTimeout

E行者 | 园豆:1761 (小虾三级) | 2021-01-06 09:16

setInterval不是只能针对单个函数吗,要咋实现

支持(0) 反对(0) 另一种开始 | 园豆:119 (初学一级) | 2021-01-06 18:54

@另一种开始: 函数内部控制依次调用哪些方法,比如将各个方法放在一个数组中,然后根据索引依次访问,使用一个全局变量记录当前数组索引,每次索引加1调用对应的方法,如果当前索引为最后一个,那么下一个索引重置为0,以此类推

支持(0) 反对(0) E行者 | 园豆:1761 (小虾三级) | 2021-01-07 08:25
0
小小咸鱼YwY | 园豆:3210 (老鸟四级) | 2021-01-06 11:50
0

通过setTimeout图片轮播,淡入淡出,渐入渐出,都可以用这个去作为基本的练习题目

秋北先生IT | 园豆:215 (菜鸟二级) | 2021-01-06 22:06
0
另一种开始 | 园豆:119 (初学一级) | 2021-01-06 22:32
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册