SuperYan - JavaScript https://www.hblyan.com/tag/JavaScript/ 实现一个函数只能执行一次的功能 https://www.hblyan.com/archives/147.html 2023-05-26T17:47:00+08:00 背景:应用页面有些函数方法只需要调用一次方案:闭包变量控制函数执行应用:初始化操作、异步请求、异步请求、单例模式等 var once = function(fn) { let used = false return function (...args) { if (!used) { used = true return fn(...args) } } }; //或者 var once = function(fn) { return function(...args){ try{ return fn(...args) } finally{ fn=()=>{} } } }; function greet(name) { console.log(`Hello, ${name}!`); } const greetOnce = once(greet); greetOnce('Alice'); // Hello, Alice! greetOnce('Bob'); // undefined应用初始化操作:某些初始化操作只需要在应用程序启动时执行一次,例如设置全局配置、注册事件监听器或加载资源等。使用函数只能执行一次的封装,可以确保这些初始化操作只会在应用程序启动时执行一次。事件绑定:在 JavaScript 中,我们经常需要将事件处理程序绑定到 DOM 元素的事件上。如果希望确保事件处理程序只被绑定一次,以避免重复触发问题,可以使用函数只能执行一次的封装来实现。异步请求:在进行异步请求时,有时只需要在第一次请求时执行一些特定逻辑,例如发送统计信息、记录请求日志等。通过使用函数只能执行一次的封装,可以确保这些逻辑只会在第一次请求时执行一次。单例模式:在某些情况下,我们需要确保某个类或对象只能被实例化一次,以保持全局唯一性。函数只能执行一次的封装可以用于实现单例模式,确保只有在第一次调用时才会创建该类或对象的实例。 【性能优化】利用Promise控制请求并发数量(批量图片上传) https://www.hblyan.com/archives/125.html 2023-02-22T19:18:00+08:00 背景:因为JavaScript运行是单线程的,但是可以利用异步的promise去同时发出多个网络请求,但是一次过多的请求就会造成服务器压力或者其他复杂逻辑的负担等。方案:利用promise限制同一时间调用的请求应用:图片获取、文件上传等刚开始 我的想法是利用 promise.all([...])的想法,虽然这个很容易就可以实现,但是有一个弊端就是等所有的all执行完才能执行下一次,那么能不能再次基础上,保证并发的过程中一直是达到我们的limit值呢而不会空闲?看下面这个图,当我们有无数个请求时候,我只给当前线程开辟同时调用四个api的坑位,那么哪一个坑位结束就需要下一个顶上,同时保证中间的坑位一直是满的,那么就实现了并发限流的目的了。/** * len 请求的总数量 * limit 坑位的数量 */ function limitPromise(len = 10, limit) { let count = 0; //当前执行的promise数量,记录已占有的坑位 let finishCount = 0; //已经完成的数量 function run() { return new Promise((res, rej) => { count++ //有一个新的人 入坑了 let time = Math.floor(Math.random() * 10 * 1000) console.log(time); //记录需要占坑的时间 console.log(new Date()); //入坑的时间 setTimeout(() => { res("成功") }, time) }).then(res => { count-- // 离开坑过后,空闲坑位 finishCount++ //总数+1 console.log(`已上传 ${finishCount}`); if (finishCount <= len && count <= 3) { //如果总数还有剩余,坑位还有剩余 那么执行一下操作 run() //继续入坑 } else { console.log("执行完毕"); } }) } for (let i = 0; i < limit; i++) { //初始化 开辟坑位 run() } } limitPromise(10, 3) 执行结果如上: 可以看到初始化3个坑位,然后每次有坑位执行完下一个请求就会进入,知道完成全部的操作。每次并发的最多只有3个~以上大致 的意思 应该能看明白,实际场景只需要替换len 和每次执行的异步操作即可~ 什么是event loop事件循环机制? https://www.hblyan.com/archives/90.html 2022-12-28T22:21:00+08:00 推荐一款可以在线可视化代码运行顺序的网站[link][item desc='可视化运行代码' name="loupe" link="http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D" pic="https://hblyan.oss-cn-beijing.aliyuncs.com/blog/1672238207788.jpg"][/link]event loop它的执行顺序:先执行同步,然后执行异步(微任务,宏任务)执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列同步执行完,检查微任务列表,有则依次执行,直到全部执行完,然后执行宏任务执行浏览器UI线程的渲染工作检查是否有Web Worker任务,有则执行执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空微任务包括:MutationObserver、Promise.then()或catch()、Promise为基础开发的其它技术,比如fetch API、V8的垃圾回收过程、Node独有的process.nextTick。宏任务包括:script 、setTimeout、setInterval 、setImmediate 、I/O 、UI rendering