您的位置:首页 > 健康 > 美食 > 国际调解院 香港_天下商机创业网_百度竞价推广课程_搜索引擎收录查询工具

国际调解院 香港_天下商机创业网_百度竞价推广课程_搜索引擎收录查询工具

2024/12/23 3:06:24 来源:https://blog.csdn.net/m0_65985318/article/details/143227922  浏览:    关键词:国际调解院 香港_天下商机创业网_百度竞价推广课程_搜索引擎收录查询工具
国际调解院 香港_天下商机创业网_百度竞价推广课程_搜索引擎收录查询工具

总结下前端的同步异步、事件循环问题,如有错误欢迎指正。

目录

一、setTimeout定时器函数

1.定义

2.基本语法

3.返回值

4.使用

1)异步执行

2)嵌套使用

3)事件循环

二、Promise

1.定义

2.状态

3.基本语法

1)resolve()

2)创建Promsie

3)处理Promise结果

(1)then回调(成功):

(2)catch(失败)

4.多个Promise组合使用

1)Promise.all

2)Promise.race

三、async/await

1.定义

2.async函数的特性

1)返回值是Promise

2)内部可以包含await关键字

3.await关键字的特性

1)暂停函数执行

2)只能在async函数内部使用

3)处理Promise结果

四、事件循环

1.定义

2.主要组成部分

1)执行栈

(1)作用

(2)原则

2)堆

3)任务队列(Task Queue)/消息队列(Message Queue)

(1)作用

(2)分类

3.执行流程

五、示例解析

1.例题一

1)输出结果

2)解析

2.例题二

1)输出结果

2)解析

3.例题三

1)输出结果

2)解析


一、setTimeout定时器函数

1.定义

是JavaScript中的一个定时器函数,主要作用是在指定的延迟时间(以毫秒为单位)后执行一次给定的函数或代码段。

2.基本语法

let timerId = setTimeout(function, delay, [arg1, arg2, ...]);

  • function:要延迟执行的函数。
  function myFunction() { console.log('Delayed message');}setTimeout(myFunction, 1000);
  • delay:延迟的时间,单位为毫秒。
  function myFunction() { console.log('Delayed message'); }setTimeout(myFunction, 1000);
  • [arg1, arg2, ...]:可选参数。
function addNumbers(a, b) { console.log(a + b); 
}setTimeout(addNumbers, 1000, 3, 5);

3.返回值

setTimeout函数会返回一个定时器的标识符(timerId)。这个标识符可用于在定时器执行之前取消定时器,通过clearTimeout函数来实现。

  let timerId = setTimeout(function() { console.log('This message will not be shown.'); }, 3000);clearTimeout(timerId);

代码通过clearTimeout函数取消了设置的定时器,console.log将不会被输出。

4.使用

1)异步执行

setTimeout是一种异步操作方式。当代码执行到setTimeout函数时,不会阻塞后续代码的执行。

console.log('Start');
setTimeout(function() { console.log('Delayed');}, 2000);
console.log('End');

在以上函数中,输出顺序是Start、End,然后2秒后输出Delayed。因为setTimeout中的函数被放入了宏任务队列,等当前执行栈中的代码执行完后,才会在2秒后执行setTimeout中的函数。

2)嵌套使用

实现更复杂的定时效果,比如模拟一个倒计时。

function countdown(seconds) {if (seconds < 0) {return;}console.log(seconds);let timerId = setTimeout(() => {countdown(seconds - 1);}, 1000);
}
countdown(5);

这个函数会从5开始每秒递减数字,直到输出0,是一个简单的倒计时器。

3)事件循环

事件循环中,setTimeout中的函数会被放入宏任务队列

二、Promise

1.定义

Promise在JavaScript中用于处理异步操作的结果。它是一个对象,用于包装一个还未完成的异步操作,可以在操作完成后进行相应的结果处理。

2.状态

  • Pending(进行中):Promise的初始状态。当一个Promise被创建但异步操作尚未完成时,处于这个状态。
  • Fulfilled(已成功):当异步操作完成时,Promise的状态变为Fulfilled。例如,一个fetch请求成功获取到数据后,对应Promise就会进入Fulfilled状态。
  • Rejected(已失败):如果异步操作出现错误,Promise就会进入Rejected状态。比如,网络请求出现错误或者读取文件失败等情况。

3.基本语法

1)resolve()

(1)调用resolve()

当在一个Promise的执行器函数(传递给new Promise()的函数)中调用resolve()时,这个Promise就会从pending(进行中)状态转变为fulfilled(已成功)状态。表明这个Promise被解决了,并且任何与该Promise关联的then()方法中的成功回调函数将会被调用,同时将resolve()的参数作为成功回调函数的参数传递进去。

(2)没有调用resolve()的情况

保持pending状态:

如果没有调用resolve(),并且也没有调用reject(),Promise会一直保持pending状态。这种状态下,与该Promise关联的then()方法中的成功回调函数不会被调用,因为Promise尚未被成功解决。

可能导致的问题:

  • 内存泄漏风险:如果有大量的Promise一直处于pending状态,并且这些Promise及其关联的对象(如回调函数)等没有被正确清理,那未完成的Promise所占用的内存空间就无法被释放,可能会导致内存泄漏。
  • 程序逻辑阻塞:某些情况下,其他依赖于这个Promise结果的代码部分可能会被无期限地阻塞等待。

2)创建Promsie

let myPromise = new Promise((resolve, reject) => {// 异步操作if (/* 异步操作成功 */1) {resolve('成功的结果');} else {reject('失败的原因');}
});

3)处理Promise结果

(1)then回调(成功):
myPromise.then((result) => { console.log(result); });

当Promise进入Fulfilled状态时,then方法中的回调函数会被调用,并传入成功的结果,可进行一些后续操作,如UI显示等。

(2)catch(失败)
myPromise.catch((error) => { console.log(error); });

当Promise进入Rejected状态时,catch中的方法会被调用,用于处理错误。

4.多个Promise组合使用

1)Promise.all

Promise.all用于同时处理多个Promise。它接受Promise数组作为参数,并返回一个新的Promise。当数组中的所有Promise都进入Fulfilled状态时,新的Promise才会进入Fulfilled状态,并且返回一个包含所有成功结果的数组。

let promise1 = new Promise((resolve) => {resolve('promise1的结果');
});
let promise2 = new Promise((resolve) => {resolve('promise2的结果');
});
Promise.all([promise1, promise2]).then((results) => {console.log(results); // ['promise1的结果', 'promise2的结果']
});

2)Promise.race

和Promise.all类似,但它只关心第一个完成的Promsie(无论成功还是失败)。当第一个Promise完成后,返回的新Promise就会采用这个最先完成的Promsie的状态和结果

let fastPromise = new Promise((resolve) => {setTimeout(() => {resolve('fastPromise的结果');}, 1000);
});
let slowPromise = new Promise((resolve) => {setTimeout(() => {resolve('slowPromise的结果');}, 2000);
});
Promise.race([fastPromise, slowPromise]).then((result) => {console.log(result); // 'fastPromise的结果'
});

三、async/await

1.定义

async/await是JavaScript中处理一步操作的一种更简洁、更易于理解的语法糖,它是基于Promise构建的。async用于定义一个异步函数,而await用于暂停异步函数的执行,直到一个Promise被解决(Fulfilled或Rejected)。

2.async函数的特性

1)返回值是Promise

一个async函数总是返回一个Promise。如果函数内部没有显式地返回一个Promise,JavaScript会自动将返回值包装在一个resolved的Promise中。

async function myAsyncFunction() {return "Hello";
}

以上代码等同于:

function myAsyncFunction() {return Promise.resolve("Hello");
}

2)内部可以包含await关键字

async函数的主要作用是可以在其中使用await来处理异步操作。不过,await只能在async函数内部使用。

3.await关键字的特性

1)暂停函数执行

当async函数执行到await关键字时,函数的执行会暂停直到后面跟着的Promise被解决

async function asyncFunction() {console.log("Before await");let result = await new Promise((resolve) => {resolve("Resolved");});console.log(result);console.log("After await");
}
asyncFunction();

调用函数中,会先输出"Before await",然后await关键字等待Promise的解决,resolve()

2)只能在async函数内部使用

await只能在async函数内部使用。如果在非async函数中使用await,会导致语法错误。这是因为await依赖于async函数提供的异步执行上下文。

3)处理Promise结果

await会获取Promise的解决值(fulfilled)或抛出异常(rejected)。

async function handlePromise() {try {let response = await fetch('https://example.com/api');let data = await response.json();return data;} catch (error) {console.error("An error occurred:", error);throw error;}
}

四、事件循环

1.定义

事件循环(Event Loop)是JavaScript的运行机制,用于处理异步任务。

它像一个永不停歇的循环,不断检查任务队列,并执行其中的任务,从而让JavaScript能够在单线程的环境下处理各种异步操作,如定时器、网络请求、用户事件等。

2.主要组成部分

1)执行栈

(1)作用

执行栈是JavaScript代码执行的地方,它是一个栈结构。当一个函数被调用,它的执行上下文会被压入执行栈。函数执行完毕后,其执行上下文会从栈顶弹出。例如,当执行

function a() { console.log('a'); } a();

时,a函数的执行上下文会被压入执行栈,执行console.log('a')后,函数执行完毕,执行上下文从栈顶弹出。

(2)原则

执行栈遵循先进后出的原则,当一个函数内部调用另一个函数时,新函数的执行上下文会被压入栈顶,等新函数执行完毕后才会弹出,然后继续执行原理函数的剩余部分。

2)堆

堆是用于存储对象和函数的内存空间。在JavaScript中,当创建一个对象或者一个函数时,这些数据会被存储在堆中。堆的内存分配和回收由JavaScript的垃圾回收机制来管理。

3)任务队列(Task Queue)/消息队列(Message Queue)

(1)作用

任务队列用于存放异步任务,如setTimeout、setInterval、Promise的then回调等。它是一个先进先出的队列结构。当异步任务可以执行时(比如setTimeout的延迟时间到了或者Promise的状态改变了),任务会被放入任务队列。

(2)分类

任务队列分为宏任务队列微任务队列。宏任务队列主要存放如setTimeout、setInterval、I/O操作、script(整体代码块)等任务;微任务队列主要存放Promise的then回调、async/await的后续操作等任务。

3.执行流程

(1)首先,JavaScript引擎会执行全局代码(script),将其压入执行栈。执行过程中,遇到同步代码,就直接执行;如果遇到异步操作,会将异步操作的相关任务交给浏览器或Node.js的其他模块(如Web API模块)去处理,执行栈继续执行其他同步代码。

(2)异步操作完成时,其对应的任务会被放入任务队列

(3)执行栈为空后,事件循环会先检查微任务队列。如果微任务队列中有任务,就将任务逐个取出并压入执行栈执行,直到微任务队列为空。

(4)微任务队列清空后,事件循环会检查宏任务队列。如果宏任务队列中有任务,就取出一个任务压入执行栈执行,这个任务执行完毕后,又回去检查微任务队列中是否有新任务(因为在宏任务执行过程中可能产生新的微任务),如此循环

五、示例解析

1.例题一

先来个比较简单的:

async function async1() {console.log('async1 start');let result = await async2();console.log(result);console.log('async1 end');
}
async function async2() {console.log('async2');
}
console.log('start');
async1();
console.log('end');

1)输出结果

2)解析

(1)执行同步代码

首先执行同步代码console.log('start'),输出'start'

(2)调用async1()

进入async1函数内部,console输出'async1 start'

await关键字异步操作,等待async2返回一个Promise,并且把Promise的返回值赋值给了result变量。

(4)执行async2()

执行async2异步函数,进入后console输出'async2'

async2执行完毕,返回一个Promise(因为没有显式地返回一个值,JavaScript会自动将其包装为一个已解决的Promise,值为undefined)

(6)回到async1函数

由于await的作用,async1函数暂停执行,等待async2返回的Promise被解决。

(7)执行同步代码

异步操作不会阻塞其他同步代码,按顺序执行console.log('end'),输出'end'

(8)回到async1

async2返回的Promise被解决(实际上它立即被解决,因为没有异步操作等待,只是一个console),async1继续执行,将async2的返回值undefined赋值给result,输出'undefined',最后输出'async1 end'

2.例题二

对例题一进行改变,得到如下:

  async function async1() {  console.log('async1 start');await async2().then((res) => {console.log(res);});console.log('async1 end');}async function async2() {  console.log('async2');return new Promise((resolve, reject) => {console.log('async2 promise');setTimeout(() => {resolve('async2 resolve');}, 2000);});}async1();console.log('end');

1)输出结果

2)解析

(1)首先执行async1()

进入async1函数,直接console.log输出'acync1 start'

遇到await async1(),开始执行async2()

(2)执行async2()

先直接console.log输出'async2'

接下来是创建一个Promise,这个Promise中直接输出'async2 promise'

遇到setTimeout定时器,会将setTimeout中的函数放入宏队列

此时async2()中的Promise的状态还没有变为fulfilled,所以async2()执行暂停并返回一个处于pending状态的Promsie。

(3)回到async1()

由于await的作用,async1函数暂停执行,等待async2返回的Promise被解决。

(4)执行console.log('end')

先执行其他同步代码,输出'end'

(5)定时器触发

事件循环检查微任务队列中没有任务,检查宏任务队列中有一个setTimeout定时器的函数,在经过2000毫秒后,setTimeout的回调函数被执行,此时,在async2中创建的Promise调用resolve('async2 resolve'),Promise的状态变为fulfilled已解决

(6)回到async1()

当async2返回的Promise被解决后,async1中的Promise的then回调函数被放入微队列任务中等待执行。

当执行栈为空时,事件循环检查微任务队列,执行then回调函数,输出res,res的值也就是之前resolve()中返回的值,输出'async2 resolve'

接着继续执行async1中await之后的代码,输出'async1 end'

3.例题三

对例题二再进行改变,得到如下:

async function async1() {console.log('async1 start');await async2().then((res) => {console.log(res);});console.log('async1 end');
}async function async2() {console.log('async2');new Promise((resolve, reject) => {console.log('async2 promise');resolve('async2 resolve');setTimeout(() => {console.log('settimeout');}, 0);}).then((res) => { console.log(res); })return await async3();
}
async function async3() {console.log('async3');return 'async3 resolve';
}
console.log('start');
async1();console.log('end');

1)输出结果

2)解析

(1)执行同步代码

console.log输出'start'

(2)执行async1()

首先输出'async1 start',然后遇到await关键字等待async2执行。

(3)执行async2()

console输出'async2',然后用new创建一个Promise对象,这个Promise中输出'async2 promise',然后调用resolve('async2 resolve')将这个Promise的状态改为了fulfilled,这时将Promise的then回调函数放入微任务队列中等待执行,也就是将console.log(res)放入微队列

接着遇到setTimeout定时器,将定时器的函数放入宏队列中,即将console.log('settimeout')放入宏队列中。

return await async3()中遇到await关键字,等待async3执行。

(4)执行async3()

在async3中直接console输出'async3',然后retuen 'async3 resolve',async函数中的return是一个Promise对象,这个对象返回值为'async3 resolve'。

(5)回到async2()

async2中获取到了async3返回的值,并且将该值return,async2函数也返回一个Promise对象,对象值是'async3 resolve'。

(6)回到async1()

这时await async2()获取到了async2函数的返回值,并且Promise状态为fulfilled已完成,所以会将Promise的回调函数then函数放入微任务队列中。

(7)执行console.log('end')

输出'end'

(8)检查微任务队列

这时微任务队列里第一个是async2函数中的Promise的then回调函数(函数作用是console.log(res)),第二个是async1函数中async2执行完毕后的then回调函数(函数作用是console.log(res))。先进先出,按照顺序执行。先输出'async2 promise',再输出'async3 resolve'。这时async1的await执行完毕,async1函数继续执行,输出'async1 end'

(9)检查宏任务队列

宏队列中只存放了async2函数中的setTimeout定时器,触发定时器,在0毫秒之后输出'settimeout'

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com