首页 > 系统相关 >js 栈追踪与内存管理

js 栈追踪与内存管理

时间:2024-01-20 19:02:11浏览次数:36  
标签:异步 fooPromiseExecutor 函数 js 内存 期约 foo 追踪

期约与异步函数的功能有相当程度的重叠,但它们在内存中的表示则差别很大。看看下面的例子, 它展示了拒绝期约的栈追踪信息:

function fooPromiseExecutor(resolve, reject) {
     setTimeout(reject, 1000, 'bar');
}
   function foo() {
     new Promise(fooPromiseExecutor);
}foo();
// Uncaught (in promise) bar // setTimeout
// setTimeout (async)
// fooPromiseExecutor
// foo

根据对期约的不同理解程度,以上栈追踪信息可能会让某些读者不解。栈追踪信息应该相当直接地 表现 JavaScript 引擎当前栈内存中函数调用之间的嵌套关系。在超时处理程序执行时和拒绝期约时,我 们看到的错误信息包含嵌套函数的标识符,那是被调用以创建最初期约实例的函数。可是,我们知道这 些函数已经返回了,因此栈追踪信息中不应该看到它们。

答案很简单,这是因为 JavaScript 引擎会在创建期约时尽可能保留完整的调用栈。在抛出错误时, 调用栈可以由运行时的错误处理逻辑获取,因而就会出现在栈追踪信息中。当然,这意味着栈追踪信息 会占用内存,从而带来一些计算和存储成本。 如果在前面的例子中使用的是异步函数,那又会怎样呢?比如:

function fooPromiseExecutor(resolve, reject) {
      setTimeout(reject, 1000, 'bar');
}
async function foo() {
await new Promise(fooPromiseExecutor);
} foo();
    // Uncaught (in promise) bar
    //   foo
    //   async function (async)
    //   foo

这样一改,栈追踪信息就准确地反映了当前的调用栈。fooPromiseExecutor()已经返回,所以 它不在错误信息中。但 foo()此时被挂起了,并没有退出。JavaScript 运行时可以简单地在嵌套函数中 存储指向包含函数的指针,就跟对待同步函数调用栈一样。这个指针实际上存储在内存中,可用于在出 错时生成栈追踪信息。这样就不会像之前的例子那样带来额外的消耗,因此在重视性能的应用中是可以 优先考虑的。

掌握单线程 JavaScript 运行时的异步行为一直都是个艰巨的任务。随着 ES6 新增了期约 和 ES8 新增了异步函数,ECMAScript 的异步编程特性有了长足的进步。通过期约和 async/await,不仅 可以实现之前难以实现或不可能实现的任务,而且也能写出更清晰、简洁,并且容易理解、调试的代码。

期约的主要功能是为异步代码提供了清晰的抽象。可以用期约表示异步执行的代码块,也可以用期 约表示异步计算的值。在需要串行异步代码时,期约的价值最为突出。作为可塑性极强的一种结构,期 约可以被序列化、连锁使用、复合、扩展和重组。

异步函数是将期约应用于 JavaScript 函数的结果。异步函数可以暂停执行,而不阻塞主线程。无论 是编写基于期约的代码,还是组织串行或平行执行的异步代码,使用异步函数都非常得心应手。异步函 数可以说是现代 JavaScript 工具箱中最重要的工具之一。

标签:异步,fooPromiseExecutor,函数,js,内存,期约,foo,追踪
From: https://blog.51cto.com/u_16251183/9346037

相关文章

  • js 串行执行期约
    用数组和for循环再包装一下就是:asyncfunctionrandomDelay(id){//延迟0~1000毫秒constdelay=Math.random()*1000;returnnewPromise((resolve)=>setTimeout(()=>{console.log(`${id}finished`);resolve();},delay));}asyncfunctionfoo(){......
  • js 异步函数策略
    因为简单实用,所以异步函数很快成为JavaScript项目使用最广泛的特性之一。不过,在使用异步函数时,还是有些问题要注意。实现sleep()很多人在刚开始学习JavaScript时,想找到一个类似Java中Thread.sleep()之类的函数,好在程序中加入非阻塞的暂停。以前,这个需求基本上都通过set......
  • js 停止和恢复执行
    使用await关键字之后的区别其实比看上去的还要微妙一些。比如,下面的例子中按顺序调用了3个函数,但它们的输出结果顺序是相反的:asyncfunctionfoo(){console.log(awaitPromise.resolve('foo'));}8asyncfunctionbar(){console.log(await'bar');}asyncfun......
  • js await 的限制
    等待会抛出错误的同步操作,会返回拒绝的期约:```jsasyncfunctionfoo(){console.log(1);await(()=>{throw3;})();}//给返回的期约添加一个拒绝处理程序foo().catch(console.log);console.log(2);//1//2//3```如前面的例子所示,单独的Promise.reject()不会被异步函......
  • js 异步函数的返回值
    函数可以得到它返回的期约:asyncfunctionfoo(){console.log(1);return3;}//给返回的期约添加一个解决处理程序foo().then(console.log);console.log(2);//1//2//3当然,直接返回一个期约对象也是一样的:asyncfunctionfoo(){console.log(1);returnProm......
  • Visual Studio Code 解决JSON中不允许注释?
    1.使用vscode打开json文件后,一些注释显示如图所示,有红色波浪线,影响阅读 2.悬浮在波浪线报错信息,会弹出提示ViewProblem,提示问题是:json文件中不允许注释 3.下面图片表示json文件中不允许注释 4.点击底部工具栏的JSON 5.弹出的窗口中输入jsonwithComments,找......
  • .NET字符串内存管理:常量字符串、动态创建和字符串池的巧妙结合
     在.NET中,字符串是不可变的,这意味着一旦创建,字符串的内容就不能被修改。字符串在内存中以不同的方式存储,具体取决于它是常量字符串还是动态创建的字符串。常量字符串常量字符串在编译时就被解析,并在程序的元数据(Metadata)中存储。多个相同的字符串常量可能会共享同一块内存......
  • hyperexpress框架/使用uwebsockets.js核心
    import{scheduleJob}from'node-schedule';//定时任务functionsetupScheduledTasks(){//每6秒执行一次setInterval(()=>{taskEverySixSeconds();},6000);//每33分钟执行一次setInterval(()=>{taskEve......
  • java面向对象基础语法之两个对象的内存图
    一:概述在相关文章前面说明了一下一个对象的内存图,在这里将继续说明两个对象的内存图。二:具体说明<1>实例代码Student类publicclassStudent{Stringname;intage;Stringaddress;publicvoidstudy(){......
  • 模块-包-commandJs
    模块、包、commandJs01为什么要有模块化开发? 在传统的nodejs代码开发中,把js文件拆分开来有很糟糕的编程体验,在开发者引入的js文件时,方法名相同时后者将覆盖前面的方法去执行 我们可以把公共的功能抽离成为一个单独的JS文件作为一个模块,默认情况下这个模块里面的方法或书写,......