[JavaScript] [5] Timer (including callback function and Promise)


foreword

什么是定时器
JavaScript provides the function of executing code at regular intervals, called a timer, which is mainly completed by the two functions setTimeout() and setInterval(). They add cron tasks to the task queue.


了解回调函数和Promise对象

1. Callback function

  • You don't know when the user clicks the button. Therefore, an event handler is defined for the click event. The event handler accepts a function that is called when the event is fired.
  • A callback is simply a function that is passed as a value to another function and is only executed when an event occurs. This is done because JavaScript has top-level functions that can be assigned to variables and passed to other functions (called higher-order functions). Usually all client code is encapsulated in the window object's load event listener, which will only run when the page is ready
window.addEventListener('load', () => {
    
    
  //window 已被加载。
  //做需要做的。
})
  • Callbacks are everywhere, not just in DOM events. A common example is using timers:
setTimeout(() => {
    
    
  // 2 秒之后运行。
}, 2000)
  • XHR requests also accept callbacks, in this example assigning a function to a property that will be called when a specific event occurs (in this example, a change in state of the request):
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
    
    
  if (xhr.readyState === 4) {
    
    
    xhr.status === 200 ? console.log(xhr.responseText) : console.error('出错')
  }
}
xhr.open('GET', 'http://nodejs.cn')
xhr.send()
  • Callbacks are fine for simple scenarios! However, each callback can add levels of nesting, and when there are many, the code can quickly become very complex
window.addEventListener('load', () => {
    
    
  document.getElementById('button').addEventListener('click', () => {
    
    
    setTimeout(() => {
    
    
      items.forEach(item => {
    
    
        //你的代码在这里。
      })
    }, 2000)
  })
})

This is a simple four-level nesting, but multi-level nesting is not recommended when the nesting becomes more and more complex. Starting with ES6, JavaScript introduced some features that help in handling asynchronous code without involving the use of callbacks: Promise (ES6) and Async/Await (ES2017).

Two, promises

promise object

The Promise object is a specification proposed by the CommonJS working group to provide a unified interface for asynchronous operations.

First, it is an object, which means it can be used in the same way as other JavaScript objects; second, it acts as a proxy, acting as an intermediary between asynchronous operations and callback functions. It enables the asynchronous operation to have a synchronous operation interface, so that the program has a normal synchronous operation process, and the callback function does not need to be nested layer by layer.
Simply put, its idea is that each asynchronous task returns a Promise object immediately, and since it returns immediately, a synchronous operation process can be adopted. This Promise object has a then method that allows specifying a callback function to be called after the asynchronous task completes.

  • The asynchronous operation f1 returns a Promise object, and its callback function f2 is written as follows
(new Promise(f1)).then(f2)
  • Multi-layer callback function
//传统写法
step1(function(value1){
    
    
 step2(value1,function(value2){
    
    
  step3(value2,function(value3){
    
    
   step4(value3,function(value4){
    
    
		...
   })
  })
 })
})
//Promise写法
(new Promise(step1))
 .then(step2);
 .then(step3);
 .then(step4);

In general, the traditional way of writing callback functions makes the code cluttered and develops horizontally instead of downward. The Promises specification was proposed to solve this problem. The goal is to use the normal program flow (synchronous) to handle asynchronous operations. It first returns a Promise object, and subsequent operations are registered on this object in a synchronous manner. Wait until the asynchronous operation has a result, and then perform other operations deposited on it in the early stage.

  • Three states of the Promise object:
    asynchronous operation "pending"
    asynchronous operation "resolved" (also known as fulfilled)
    asynchronous operation "failed" (rejected)
    There are only two ways to change the three ways: never completed to Completed and Never Completed to Failed
  • The transition method can only happen once, once the status changes to "Completed" or "Failed", it means that no new status changes will occur. There are only two final states of the Promise object.
    The asynchronous operation is successful: the Promise object returns a value, and the state becomes resolved
    . The asynchronous operation fails, and the Promise object throws an error, and the state becomes rejected.
// po是一个Promise对象
//Promise对象po使用then方法绑定两个回调函数,操作成功返回console.log,操作失败返回console.error,这两个函数都接受异步操作传回的值作为参数
po.then(
  console.log,
  console.error
);
  • then method can be chained
po
 .then(step1)
 .then(step2)
 .then(step3)
 .then{
    
    
 	console.log;
 	console.error; //Promise对象的错误有传递性
 }

From a synchronization point of view, it is equivalent to

try {
    
    
  var v1 = step1(po);
  var v2 = step2(v1);
  var v3 = step3(v2);
  console.log(v3);
} catch (error) {
    
    
  console.error(error);
}

Generation of Promise objects

var promise = new Promise(function(resolve,reject){
    
    
	if(/*异步操作成功*/){
    
    
		resolve(value);
//在异步操作成功时调用,并将异步操作的结果,作为参数传递出去		
		
	}else{
    
    
		reject(error);
//在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去		
	}
})

You can use the then method

po.then(function(value){
    
    
 //success
},function(value){
    
    
 //failure
});

Loading pictures is written as a Promise

var preloadImage = function(path){
    
    
	return new Promise(function(resolve,reject){
    
    
	var image = new Image();
	image.onload = resolve;
	image.onerror = reject;
	image.src = path;
	})
}

3. The timer and the method of clearing the timer

1 The code to be deferred must be put into setTimerout in the form of a string
because the engine uses the eval function internally to convert the string into code.

setTimeout('console.log(1)',1000)

2 If the function is postponed, you can directly put the function name into setTimeout.
On the one hand, the eval function has security concerns. On the other hand, in order to facilitate the JavaScript engine to optimize the code, the setTimeout method generally uses the form of the function name

function fn(){
    
    
console.log(2);
}
setTimeout(fn,1000);
//或者
setTimeout(function(){
    
    
	console.log(2);
},1000)

3 clear timer

function fn(){
    
    
	console(2);
}
var timer = setTimeout(fn,1000);
clearTimeout(timer);

4. JD shopping cart countdown case

The layout omission code is as follows (example):

var day = document.querySelector('.day')
var hour = document.querySelector(".hour");
var minute = document.querySelector('.minute');
var second = document.querySelector(".second");
var inputTime = +new Date('2022-6-4 22:00:00')
countDown();
var timer = null;
timer = setInterval(countDown,1000);

var button2 = document.querySelector('.start');
button2.addEventListener('click',()=>{
    
    
	timer = setInterval(countDown,1000)})

var button = document.querySelector('.stop');
button.addEventListener('click',function(){
    
    
	clearTimeout(timer);
})


function countDown(){
    
    
	var nowTime = +new Date(); //返回当前毫秒数
	var	time = (inputTime - nowTime) / 1000; //时间差
	var d = parseInt(time / 60 / 60 /24);
	d = d < 10 ? '0'+d : d;
	day.innerHTML = d;

	var h = parseInt(time / 60 / 60 %24);
	h = h < 10? '0'+h : h;
	hour.innerHTML = h;

	var m = parseInt(time / 60 % 60);
	m = m < 10? '0'+m : m;
	minute.innerHTML = m;

	var s = parseInt(time % 60)
	s = s <10? '0'+s : s;
	second.innerHTML = s;
	
}

insert image description here

5. Send verification code case

The layout omission code is as follows (example):

    //1 按钮点击后,禁用按钮
    //2 同时按钮里面的内容会变化,主要button里面的内容通过innerHTML修改
    //3 秒数定义一个变量在定时器里不断递减
    //4 如果变量为0说明时间到了,停止计数器,并复原按钮初始状态
    var button = document.querySelector('button');
    var time = 10;
    button.addEventListener('click',function(){
    
    
        button.disabled = true;
        var timer = setInterval(()=>{
    
    
            if(time == 0){
    
    
                //清除定时器和复原按钮
                clearInterval(timer);
                button.disabled = false;
                button.innerHTML = '发送';    
                time = 10;
            }else{
    
    
                button.innerHTML = '还剩'+time+'秒发送';
                --time;
            }
        },1000)
    })
    // while(time == 0){
    
    
    //         button.disabled = false;
    //         button.innerHTML = '发送验证码';

    //     }尽量不去使用while

insert image description here

Summarize

Tip: Here is a summary of the article:
Promise objects still need to continue to learn. Timers need to learn to count and clear

Guess you like

Origin blog.csdn.net/weixin_51612770/article/details/125120379
Recommended