javascript

JavaScript 中内存泄漏的原因以及如何避免它们

当涉及到“老式”网页时,对内存管理的关注不足通常不会产生戏剧性的后果。当用户浏览链接并加载新页面时,每次加载都会从内存中删除页面信息。

SPA(单页应用程序)的兴起促使我们更加关注与内存相关的 JavaScript 编码实践。如果应用程序开始逐渐使用越来越多的内存,那会严重影响性能甚至导致浏览器的选项卡崩溃。

在本文中,我们将探讨导致 JavaScript 内存泄漏的编程模式,并解释如何改进内存管理。

Javascript垃圾收集以及内存泄漏

这几天在写代码的时候一直想到一个问题,内存的问题,这个问题解决不了,始终不能安安心心写代码(我这里又又又定义了一个变量,闭包能访问到它,但是我在闭包函数中并没有访问他,闭包一直存在,不占内存吗?之前也一直有一个问题,不解决也是寝食难安,见事件处理函数中this的指向以及函数上下文的继承),以前写c,c++的时候,似乎每次全局作用域有数组我不用了,我就手动给它删除了(局部变量出了作用域就自行销毁),而写javascript的时候意识到,虽然避免使用了全局变量,可是因为闭包的存在难道不会导致内存的泄漏(只要闭包函数存在,就始终拥有对外部函数的作用域的访问权限)?
之前第一次看《javascript高级程序设计》的时候,记得有一节是说垃圾回收机制,当时连对象,应用,原型什么的都没有搞清楚,那章基本上也就跳过了,现在回想起来,似乎我很少在js中对其内存进行管理,除了我不想要某个属性了,会delete一下,别的都没有进行管理,那么Js不需要内存管理吗?不会发生内存泄漏?

js垃圾回收机制

Js有自己的垃圾回收机制,会帮助开发者管理内存。回收机制会查找应用无法到达的内存。这其实跟我们的初衷是有一些细微但是很重要的差别,该机制是寻找无法到达的内存,而我们想要的其实是寻找我不会再使用的内存。一块内存(一个变量,引用),只有开发者我们自己才知道会不会再用到,而检测机制,只能检测到程序中别的地方不会再调用的内存(也正常,要是检测机制能检测到那个变量我不用了才奇怪了)。所以,如果我们不使用某个变量了,让程序别的地方都引用不到它,垃圾回收机制就能够发现并处理它,而内存泄漏的根本原因就是我们不打算继续使用的内存还存在着引用,从程序别的地方可以访问到它,就不会对其进行释放。
综上可以这么说:js的回收机制的关键是理解可到达的概念。从根(window)出发,能够到达的变量都会留在内存中,只有无法到达的节点(变量,函数)才会被回收机制回收。从而完成内存的释放。而引起内存泄漏的根本原因就是存在不想要的引用,使得不需要的内存能够从根节点到达,从而无法释放该内存。

js回收机制示例

普通对象回收机制

如下代码:

function Menu(title) {
  this.title = title
  this.elem = document.getElementById('id')
}
 
var menu = new Menu('My 

【经典面试题】js防止重复点击、防止点击过快的方法

若用户疯狂点击提交按钮,请求很多次,生成好多条数据,为了解决这种问题,通常采用以下两种简单两种方法

1.可以添加一个开关,让这个开关默认为true,第一次点击将其变为false,点击事件的执行需要判断这个开关是否为true(例如有了请求结果然后在设置为true),为true执行,false不执行

    var isclick = true;
    function fn(){
        if(isclick){
            isclick = false;
            //下面添加需要执行的事件
                ...
            console.log('点击事件');
            
        }
    }

2.防止点击过快,还可以设置定时器,让在一定时间后,自动将开关变为true,变多次执行为一段时间内的一次执行

var oldtime = '';
function preventclick(msc){
	if(oldtime==''){
		oldtime = new Date().getTime();
		return true;
	}else{
		var newtime = new Date().getTime();
		if(newtime - oldtime 

JavaScript Promises:简介

Promise 简化了延迟和异步计算。Promise 代表一个尚未完成的操作。

 

诸位开发同仁,请准备迎接 Web 开发史上的重大时刻。

[鼓声响起来]

Promise 已经来到了 JavaScript

[璀璨的烟花在天上亮起,五彩纸屑纷纷落下,人们为之疯狂]

此时此刻,您会是下列几种人之一:

  • 大家在周围欢呼,但您根本不知道这是为了什么。也许您甚至不知道这个 promise 到底是什么东西。您耸了耸肩,但肩上却感到了五彩纸屑的重量。假如是这样,请别担心,我花了很长时间才弄清楚它的重要性。您可能想从头开始了解。
  • 您兴奋地挥出一拳!可算等到了!您之前已经用过这些 Promise,但让人苦恼的是,所有的实现都采用略有不同的 API。官方 JavaScript 版本的 API 是什么?您可能想从术语开始。
  • 您对它已经有所了解了,对那些上蹿下跳的新人嗤之以鼻。花点时间享受下您的优越感,然后直接前往 API 参考吧。

理解异步 JavaScript-学习JavaScript是怎么工作的

 

理解异步 JavaScript

学习 JavaScript 是怎么工作的

照片来自 Unsplash 的作者 Sean Lim

JavaScript 是一种单线程编程语言,这意味着同一时间只能完成一件事情。也就是说,JavaScript 引擎只能在单一线程中处理一次语句。

单线程语言简化了代码编写,因为你不必担心并发问题,但这也意味着你无法在不阻塞主线程的情况下执行网络请求等长时间操作。

想象一下从 API 中请求一些数据。根据情况,服务器可能需要一些时间来处理请求,同时阻塞主线程,让网页无法响应。

这也就是异步 JavaScript 的美妙之处了。使用异步 JavaScript(例如回调,Promise 或者 async/await),你可以执行长时间网络请求同时不会阻塞主线程。

虽然您没有必要将所有这些概念都学会成为一名出色的 JavaScript 开发人员,但了解这些对你会很有帮助 🙂…

使用async属性异步加载执行JavaScript

HTML5让我兴奋的一个最大的原因是,它里面实现的新功能和新特征都是我们长久以来一直期待的。比如,我以前一直在使用placeholders,但以前必须要用JavaScript实现。而HTML5里给JavaScript标记提供的async属性,使JavaScript能异步加载执行。之前我需要各种的JavaScript插件来实现这种功能,但现在这个新属性能让我们轻松的实现异步加载。…

        

写好 JavaScript 异步代码的几个推荐做法

今天给大家来推荐几个写好 JavaScript 异步代码的推荐做法,每种场景都有一个对应的 eslint 规则,大家可以选择去配置一下。

no-async-promise-executor

不建议将 async 函数传递给 new Promise 的构造函数。

// ❌
new Promise(async (resolve, reject) => {});

// ✅
new Promise((resolve, reject) => {});

首先,你在 Promise 的构造函数里去使用 async ,那么包装个 Promise 可能就是没啥必要的。另外,如果 async 函数抛出了异常,新构造的 promise 实例并不会 reject ,那么这个错误就捕获不到了。…

现代 JavaScript,你应该使用的 10 件事,从今天开始

在Twitter 上关注我,很高兴收到您对主题或改进的建议/Chris

您可能对 JavaScript 完全陌生,或者多年来您可能只是偶尔使用它。不过有一件事很清楚 - 很多东西都发生了变化,并且您应该使用一些功能。这篇文章描述了我认为你应该每天使用的特性,如果你对 JavaScript 很认真的话

 

资源

这些是我最喜欢的 ES6+ 资源:

-1- 扩展运算符

这被表示为...一个对象或数组的前面,并完成了名字所说的,它将某些东西从一个结构变成了一个逗号分隔的列表。让我们演示一下:

展开数组

let firstHalf = [ 'one', 'two'];
let secondHalf = [

浅谈 JS 内存机制与内存泄漏

给前端食堂标星标,吃好每一顿饭!

因为公众号推荐机制变更,如果不想错过食堂的文章,可以将食堂设置为星标,这样就会出现在你的公众号置顶列表里。设置星标方式:先进入公众号后台(点击本文标题下方蓝色的字“前端食堂”),再点击右上角三个点,就可以看到设置星标啦。

前言

随着web的发展与普及,前端页面不仅只加载在浏览器上,也慢慢流行于各种app的webview里。尤其在如今设备性能越来越好的条件下,前端页面更是开始在app中担任重要的角色。如此一来,前端页面的停留时间变得更长,我们理应越发重视前端的内存管理,防止内存泄露,提高页面的性能。

想要打造高性能前端应用,防止崩溃,就必须得搞清楚JS的内存机制,其实就是弄清楚JS内存的分配与回收。

JS数据存储机制

内存空间

图片

从图中可以看出, 在 JavaScript 的执行过程中, 主要有三种类型内存空间,分别是代码空间、栈空间和堆空间。

代码空间:用来存放可执行代码

栈空间:一块连续的内存区域,容量较小,读取速度快,被设计成先进后出结构

堆空间:不连续的内存区域,容量较大,用于储存大数据,读取速度慢

数据类型

图片

JavaScript 发展至今总共有八种数据类型,其中 Object 类型称为引用类型,其余七种称为基本类型,Object 是由其余七种基本类型组成的kv结构数据。

栈空间和堆空间

栈空间其实就是 JavaScript 中的调用栈,是用来储存执行上下文,以及存储执行上下文中的一些基本类型中的小数据,如下图所示:

图片
image.png

变量环境: 存放var声明与函数声明的变量空间,编译时就能确定,不受块级作用域影响

词法环境: 存放let与const声明的变量空间,编译时不能完全确定,受块级作用域影响

而堆空间,则是用来储存大数据如引用类型,然后把他们的引用地址保存到栈空间的变量中,所以多了这一道中转,JavaScript 对堆空间数据的读取自然会比栈空间数据的要慢,可以用下图表示两者关系:

图片通常情况下,栈空间都不会设置太大,这是因为 JavaScript 引擎需要用栈来维护程序执行期间上下文的状态,如果栈空间大了的话,所有的数据都存放在栈空间里面,那么会影响到上下文切换的效率,进而又影响到整个程序的执行效率。

闭包

内部函数总是可以访问其外部函数中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包