js三座大山之异步七实现宏任务的N种方式

异步编程

js三座大山之异步一单线程,event loope,宏任务&微任务
js三座大山之异步二异步方案
js三座大山之异步三promise本质
js三座大山之异步四-Promise的同步调用消除异步的传染性
js三座大山之异步五基于异步的js性能优化
js三座大山之异步六实现微任务的N种方式
js三座大山之异步七实现宏任务的N种方式

js中现在有两类任务

一类是天然存在的在当前执行栈中按顺序依次执行的同步任务。

一类是为了解决单线程带来的问题引入的异步任务。

宏任务和微任务主要的区别体现在执行时机上,当事件循环每次执行完一个宏任务时,它会检查是否有微任务队列。如果有,那么在下一个宏任务开始之前,事件循环会一直执行微任务队列中的所有任务。也就是说,微任务的优先级高于宏任务,微任务会在任何新的宏任务开始之前执行,并且直至微任务被清空后才会执行下一个宏任务。

宏任务和微任务根据不同的触发方式 在执行时机上有所不同 其他并无区别。并不是说微任务执行性能好于宏任务。

微任务一般由JavaScript引擎发起。

宏任务一般由宿主环境(如浏览器或Node.js)发起。

实现异步宏任务的N种方式

MessageChannel 浏览器环境

提供了一种在不同文档(例如主线程和 worker 线程,或者不同的 iframes)之间,或者在同一文档的不同部分之间进行直接通信的方式。

MessageChannel 有两个属性,port1 和 port2,它们都是 MessagePort 类型的对象。你可以在一个地方使用 port1 发送消息,然后在另一个地方使用 port2 接收消息,反之亦然。

ini 复制代码
        const channel = new MessageChannel();
        channel.port1.onmessage = callback;
        const change = function () {
            channel.port2.postMessage(0);
        };
        change();

上面的代码中channel.port2将一个消息异步地发送到prot1端口,然后channel.port1.onmessage的回调函数会加入到宏任务队列等待执行。

requestAnimationFrame 浏览器环境

由浏览器在下一次重绘之前调用传入给该方法的回调函数。由于是和渲染帧同步的 所以可以认为是天然的宏任务。

javascript 复制代码
console.log('start');
requestAnimationFrame(()=>{
  console.log('requestAnimationFrame')
})
Promise.resolve().then(() => {
    console.log('Promise');
});
console.log('end');

// start end Promise requestAnimationFrame

计时器 node&浏览器

setTimeout 指定时间后将回调函数插入到任务队列中。

javascript 复制代码
setTimeout(() => {
    console.log('setInterval')
}, 1000)

setInterval 循环指定时间后将回调函数不断的插入到任务队列中

javascript 复制代码
setInterval(() => {
    console.log('setInterval')
}, 1000)

setImmediate node环境

在Node.js环境中,setImmediate函数用于将一个回调函数排入事件循环队列,它将在当前事件循环(也就是当前的宏任务)完成后,下一个事件循环开始前被执行。

javascript 复制代码
console.log('start');
setImmediate(() => {
    console.log('setImmediate');
});
Promise.resolve().then(() => {
    console.log('Promise');
});
console.log('end');

// start end Promise setImmediate

宏任务代码总结

javascript 复制代码
const macros = [{
    name: 'MessageChannel',
    test: () => {
        return (
            typeof MessageChannel !== "undefined" && typeof window !== "undefined"
        );
    },
    run: (callback: Task) => {
        const channel = new MessageChannel();
        channel.port1.onmessage = callback;
        const change = function () {
            channel.port2.postMessage(0);
        };
        change();
    },
},
{
    name: 'setImmediate',
    test: () => {
        return typeof setImmediate === "function";
    },
    run: (callback: Task) => {
        setImmediate(callback);
    },
},
{
    name: 'raf',
    test: () => {
        return (
            typeof requestAnimationFrame !== "undefined" && typeof window !== "undefined"
        );
    },
    run: (callback: Task) => {
        requestAnimationFrame(() => {
            requestAnimationFrame(callback)
        })
    }
},
{
    name: 'setTimeout',
    test: () => {
        return true;
    },
    run: (callback: Task) => {
        setTimeout(callback, 0);
    },
}]

export const macroTask = (callback: Task) => {
    const runner = macros.find((item) => item.test());
    runner && runner.run(callback);
};

github源码

相关推荐
时间的拾荒人9 小时前
Qt 多线程详解:从 QThread 到实战
开发语言·qt·面试
海绵宝宝转agent9 小时前
MySql高频面试八股开源笔记总结
mysql·面试·开源
郑州光合科技余经理9 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
小呆呆66610 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
凤城老人10 小时前
从 PyQt6 到 Electron:给 Edge TTS 做一个“多角色配音机“的踩坑手记
javascript·typescript·electron
Dovis(誓平步青云)10 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
lsc_blog11 小时前
远程和居家办公的经历,技术简历上怎么摆
面试·职场和发展·重构·pdf·求职招聘
码艺-Alimjan11 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_11 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线
IT_陈寒11 小时前
Vite静态资源导入这个坑我帮你们踩过了
前端·人工智能·后端