和我一起来看看浏览器的异步实现到底有哪些方式

简介: 前端为何会有异步这一说法,是因为前端的代码是在浏览器中运行的,而浏览器是单线程的,前端的代码是在主线程中运行的,如果有耗时的操作,就会阻塞主线程,导致页面卡顿,所以就有了异步这一说法。

前端为何会有异步这一说法,是因为前端的代码是在浏览器中运行的,而浏览器是单线程的,前端的代码是在主线程中运行的,如果有耗时的操作,就会阻塞主线程,导致页面卡顿,所以就有了异步这一说法。

1. 什么是异步

异步是指程序的执行顺序与代码的书写顺序不一致,这里的异步是指异步任务,异步任务是指不会阻塞主线程的任务,比如 setTimeoutPromiseAjax 等。

JavaScript 中,异步任务是通过回调函数来实现的,回调函数是指在异步任务执行完毕后,会调用的函数。

2. 异步的实现

2.1 回调函数

回调函数是指在异步任务执行完毕后,会调用的函数,回调函数是异步任务的一种实现方式。

console.log(1);
setTimeout(() => {
   
  console.log(2);
}, 0);
console.log(3);

// 1
// 3
// 2

上面的代码中,setTimeout 是异步任务,所以会在主线程执行完毕后,才会执行,所以会先打印 1,然后打印 3,最后打印 2。

2.2 Promise

Promise 是异步任务的另一种实现方式。

console.log(1);

Promise.resolve()
  .then(() => {
   
    console.log(2);
  })
  .then(() => {
   
    console.log(3);
  });

console.log(4);

// 1
// 4
// 2
// 3

上面的代码中,Promise.then里面的回调函数就是异步方法,所以会先打印 1,然后打印 4,最后打印 2,3。

2.3 async/await

async/await 是异步任务的另一种实现方式,本质上是类似于 Promise 的实现方式。

console.log(1);

async function async1() {
   
  await async2();
  console.log(2);
}

async function async2() {
   
  console.log(3);
}

async1();

console.log(4);

// 1
// 3
// 4
// 2

上面的代码中,async1函数中的 await async2()是异步任务,所以会先打印 1,然后打印 3,最后打印 4,2。

3. 异步的优缺点

3.1 优点

  1. 通过异步任务,可以避免阻塞主线程,提高代码的执行效率。
  2. 通过异步任务,可以实现多个任务的并行执行,提高代码的执行效率。

3.2 缺点

  1. 通过异步任务,无法获取异步任务的返回值,只能通过回调函数来获取异步任务的返回值。
  2. 需要通过回调函数来实现异步任务,回调函数的嵌套层级会很深,导致代码的可读性很差。
  3. 需要解决异步同步的问题,比如在异步任务中,如果需要使用同步任务,就可能需要使用多个回调函数来实现。

4. 异步的解决方案

4.1 Promise

Promise 是异步任务的另一种实现方式,它的优点是可以解决回调函数的嵌套问题,可以通过链式调用的方式来实现异步任务。

const promise = new Promise((resolve, reject) => {
   
  setTimeout(() => {
   
    resolve(1);
  }, 1000);
});

promise
  .then((res) => {
   
    console.log(res);
    return 2;
  })
  .then((res) => {
   
    console.log(res);
    return 3;
  })
  .then((res) => {
   
    console.log(res);
  });

// 1
// 2
// 3

上面的代码中,promise.then里面的回调函数就是异步任务,所以会先打印 1,然后打印 2,最后打印 3。

这里只讲异步,不讲Promise的其他用法,包括后面的也只是简单介绍一下使用,因为每一个都可以单独写一个章节,所以这里只需要有一个印象就可以了,感兴趣的可以去看阮一峰老师的《ES6 入门》

4.2 async/await

async/await 是异步任务的另一种实现方式,本质上是类似于 Promise 的实现方式。

async function async1() {
   
  console.log(1);

  const res = await async2();
}

async function async2() {
   
  console.log(2);
}

async1().then(() => {
   
  console.log(3);
});

console.log(4);

// 1
// 2
// 4
// 3

上面的代码如果转换成 Promise 的实现方式,就是下面这样。

function async1() {
   
  console.log(1);

  return async2().then((res) => {
   
    console.log(3);
  });
}

function async2() {
   
  console.log(2);

  return Promise.resolve();
}

async1();

console.log(4);

setTimeout

setTimeout是老牌异步任务的标杆了,他的优点就是兼容性好,缺点就是不够精确。

setTimeout(() => {
   
  console.log(1);
}, 1000);

console.log(2);

// 2
// 1

上面的代码中,setTimeout是异步任务,所以会先打印 2,然后打印 1。

setInterval

setIntervalsetTimeout的用法基本一样,只是setInterval是每隔一段时间就执行一次。

setInterval(() => {
   
  console.log(1);
}, 1000);

console.log(2);

// 2
// 1
// 1
// 1
// ...

setInterval可能会造成内存泄漏,为啥会造成内存泄露一般是因为开发者在不需要使用setInterval的时候,没有及时清除setInterval,导致setInterval一直在执行,所以会造成内存泄漏。

requestAnimationFrame

requestAnimationFrame是浏览器提供的一个 API,可以实现动画的流畅性,不同于setTimeoutsetIntervalrequestAnimationFrame是根据浏览器的刷新频率来执行的。

function animation() {
   
  console.log(1);
  requestAnimationFrame(animation);
}

animation();

console.log(2);

// 2
// 1
// 1
// 1  大约每次间隔 16ms

MessageChannel

MessageChannel可以创建一个消息通道,并且可以通过提供的两个 MessagePort 发送消息。

const channel = new MessageChannel();

channel.port1.onmessage = () => {
   
  console.log(1);
};

channel.port2.postMessage(1);

console.log(2);

// 2
// 1

MessageChannel的使用场景通常是伴随着Ifame的使用,比如在Iframe中使用MessageChannel来实现跨域通信。

MutationObserver

MutationObserver可以监听 DOM 的变化,当 DOM 发生变化时,就会触发回调函数。

const observer = new MutationObserver(() => {
   
  console.log(1);
});

observer.observe(document.body, {
   
  childList: true,
  subtree: true,
});

document.body.appendChild(document.createElement("div"));

console.log(2);

// 2
// 1

MutationObserver的使用场景通常是监听 DOM 的变化,比如监听input的变化,实时获取输入的值。

Web Worker

Web Worker是 HTML5 中新增的一个 API,它可以实现多线程的功能,可以在后台运行一个脚本,不会阻塞主线程。

const worker = new Worker("worker.js");

worker.onmessage = (e) => {
   
  console.log(e.data);
};

worker.postMessage(1);

console.log(2);

// 2
// 1

Web Worker的使用场景通常是用来做一些比较耗时的任务,比如图片压缩、视频转码等。

Service Worker

Service Worker是 HTML5 中新增的一个 API,它可以实现离线缓存,可以拦截请求,可以实现消息推送等功能。

if ("serviceWorker" in navigator) {
   
  navigator.serviceWorker.register("sw.js").then(() => {
   
    console.log("注册成功");
  });
}

console.log(2);

// 2
// 注册成功

Service Worker的使用场景通常是用来做离线缓存,比如在移动端开发中,可以将一些静态资源缓存到本地,当用户断网时,可以从本地缓存中读取资源。

总结

本文主要介绍了 JavaScript 中的宏任务和微任务,以及宏任务和微任务的执行顺序,以及 JavaScript 中的异步任务的实现原理,以及异步任务的使用场景。

当然现在使用宏任务和微任务描述事件循环已经不太合适了,因为宏任务和微任务的概念已经被废弃了,现在的事件循环已经不再区分宏任务和微任务,而是将所有的任务都放到任务队列中,然后按照先进先出的顺序依次执行。

任务队列再分其他的任务队列,比如微任务队列、宏任务队列、I/O 任务队列、UI 渲染任务队列等,每个任务队列都有自己的执行顺序,比如微任务队列中的任务都是在当前任务执行完之后立即执行,而宏任务队列中的任务都是在当前任务执行完之后,下一个事件循环才会执行。

目录
相关文章
|
前端开发 JavaScript API
浏览器原理 19 # JavaScript 引擎是如何实现 async / await 以同步的方式来编写异步代码的?
浏览器原理 19 # JavaScript 引擎是如何实现 async / await 以同步的方式来编写异步代码的?
191 0
浏览器原理 19 # JavaScript 引擎是如何实现 async / await 以同步的方式来编写异步代码的?
|
C#
浏览器扩展系列————异步可插入协议(pluggable protocol)的实现
原文:浏览器扩展系列————异步可插入协议(pluggable protocol)的实现       IE中有很多我们比较熟悉的协议,如http,https,mailto,ftp等。当然你也可以实现自己定义的协议,稍微谈一下这里所说的协议,从我的理解来说这里的协议只有当你的网页引用某个资源时才会调用,而不是随便在某个属性的值前面加上某个协议的名称就可以了。
1128 0
|
2月前
|
JSON 移动开发 JavaScript
在浏览器执行js脚本的两种方式
【10月更文挑战第20天】本文介绍了在浏览器中执行HTTP请求的两种方式:`fetch`和`XMLHttpRequest`。`fetch`支持GET和POST请求,返回Promise对象,可以方便地处理异步操作。`XMLHttpRequest`则通过回调函数处理请求结果,适用于需要兼容旧浏览器的场景。文中还提供了具体的代码示例。
在浏览器执行js脚本的两种方式
|
2月前
|
JavaScript 前端开发 数据处理
模板字符串和普通字符串在浏览器和 Node.js 中的性能表现是否一致?
综上所述,模板字符串和普通字符串在浏览器和 Node.js 中的性能表现既有相似之处,也有不同之处。在实际应用中,需要根据具体的场景和性能需求来选择使用哪种字符串处理方式,以达到最佳的性能和开发效率。
|
2月前
|
算法 开发者
Moment.js库是如何处理不同浏览器的时间戳格式差异的?
总的来说,Moment.js 通过一系列的技术手段和策略,有效地处理了不同浏览器的时间戳格式差异,为开发者提供了一个稳定、可靠且易于使用的时间处理工具。
55 1
|
2月前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
216 1
|
3月前
|
机器学习/深度学习 自然语言处理 前端开发
前端大模型入门:Transformer.js 和 Xenova-引领浏览器端的机器学习变革
除了调用API接口使用Transformer技术,你是否想过在浏览器中运行大模型?Xenova团队推出的Transformer.js,基于JavaScript,让开发者能在浏览器中本地加载和执行预训练模型,无需依赖服务器。该库利用WebAssembly和WebGPU技术,大幅提升性能,尤其适合隐私保护、离线应用和低延迟交互场景。无论是NLP任务还是实时文本生成,Transformer.js都提供了强大支持,成为构建浏览器AI应用的核心工具。
687 1
|
3月前
|
JavaScript API
深入解析JS中的visibilitychange事件:监听浏览器标签间切换的利器
深入解析JS中的visibilitychange事件:监听浏览器标签间切换的利器
197 0
|
4月前
|
JavaScript 前端开发
js之浏览器对象|28
js之浏览器对象|28