被js的setTimeout搞得头疼

2021-01-25 10:34发布

在学习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的练习题(注意是能动手代码练习的,不是教程解说)

标签:
6条回答
迷人小祖宗
4楼-- · 2021-01-25 11:21

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

查看更多
虎瘦雄心在
5楼-- · 2021-01-25 11:25

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

查看更多
够拽才男人
6楼-- · 2021-01-25 11:26
欢心
7楼-- · 2021-01-25 11:36

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

查看更多
登录 后发表回答