GVKun编程网logo

用好js与nodejs中的try...catch(nodejs try catch)

11

这篇文章主要围绕用好js与nodejs中的try...catch和nodejstrycatch展开,旨在为您提供一份详细的参考资料。我们将全面介绍用好js与nodejs中的try...catch的优缺

这篇文章主要围绕用好js与nodejs中的try...catchnodejs try catch展开,旨在为您提供一份详细的参考资料。我们将全面介绍用好js与nodejs中的try...catch的优缺点,解答nodejs try catch的相关问题,同时也会为您带来extjs与nodejs的区别、JS与Node.js中的事件循环、JS与Node.js中的事件循环详解、js与nodejs的区别 ,http协议,的实用方法。

本文目录一览:

用好js与nodejs中的try...catch(nodejs try catch)

用好js与nodejs中的try...catch(nodejs try catch)

对异常的捕获和处理是提高程序鲁棒性的一个重要方式,即使在javascript/nodejs等看似“很难写出bug”的弱类型语言里,异常捕获处理仍至关重要,这主要是因为:

1.在一个代码块里,如果程序运行过程中自动、或主动(new Error/Exception)生成异常/错误后,若不主动去try...catch该异常,这个异常会逐层抛出,直至主程序,系统会按照框架默认方式处理该异常。

2.在逐层抛出异常的过程中,每层代码块异常点之后的程序不会再被执行,除非进行try...catch异常处理。

我们看几个简单的例子来验证一下。

(() => {
  try{
    (()=>{
      nonExistentFunction();
      console.log(''c'');
    })();
    console.log( ''b'' );
  }catch(e){
    console.log( e );
  }
})();
console.log( ''a'' );

 打印结果:

即,打印了最外层的catch内的异常处理信息和主程序接下来的部分,根据1,2可知,如果匿名函数最外层没有进行try...catch处理的话,a也不会被打印出来。

这意味着,即使是“很难写出bug”的javascript也可能因为一个小小的异常导致整个程序歇菜!try...catch则是保证主干按流程执行完毕的关键实现。

 

容易被误处理的异步异常

在nodejs等异步IO密集场景,经常用异步回调函数来处理IO操作结果——不管是正确的数据还是异常Error,但此时的try...catch怎么来写?

const fs = require(''fs'');
try{
  fs.readFile( __dirname+''/15_fs1.js'',(err,data) =>{
      if( err ){
        throw err;
      }else{
        console.log( data );
      }
  } );
}catch(err){
  console.log( ''an error occured!'',err );
}

console.log( ''hhh'' );

在文件不存在的情况下,按照try..catch的作用,我们认为应该在catch里捕捉到异常并执行异常处理语句,即打印“an error occured!XXX”;但实际结果呢?

即,异常最后并未被目前缩写的catch所捕获,而是最终被系统级捕获并按照框架方式打印出了错误信息,这是为什么呢?主要是因为try...catch是代码块,是被同步解析的,当代码执行到try后,开始读文件操作,等待异步执行结果,但catch语句是紧接着try进行的,它并不会等待异步执行的结果,因此,当执行到catch的时候,回调里的throw error还没执行呢,当然catch不到了,主程序继续解析执行直到打印出''hhh''。随后当异步会调离throw err的时候没有catch可以捕获的到,只能层层抛出到最外层,由框架来捕获和执行。

理解上述内容后,就该想到问题的关键点是try...catch的执行ticker与回调函数ticker不同步的问题,解决的办法也很简单,同步try...catch与callback函数的时钟—将try..catch放在callback里面。

正确的代码示例:

const fs = require(''fs'');

fs.readFile( __dirname+''/15_fs1.js'',(err,data) =>{
  try{
    if( err ){
      throw err;
    }else{
      console.log( data );
    }
  }catch(e){
    console.log( e );
  }
} );
console.log( ''hhh'' );

打印结果:

19年要在使用新框架写好业务逻辑的基础上,提高自己输出代码的鲁棒性,经常去分析、反思可能出现异常的模块并进行forecast error的捕获处理,进一步提高自己的代码水平。

 ——学无止境,保持好奇。May stars guide your way.

 

extjs与nodejs的区别

extjs与nodejs的区别

在前端开发和后端开发方面,extjs和node.js各自有其重要的作用。前者是基于javascript的图形用户界面框架,用于构建富客户端web应用程序,后者是一个基于事件驱动和非阻塞i/o模型的服务器端js运行环境,适用于高效处理并发请求。本文将着重分析这两种技术的区别。

  1. 技术定位

首先明确一下,ExtJS是一个前端框架,它专注于处理用户界面方面的需求,包括UI组件、数据绑定、表格等一系列功能,提供了完整的MVC结构的模型,并将其封装成了可重用、高扩展性的组件,开发者可以通过对这些组件的修改来实现个性化的定制。

与之相反,Node.js是一个后端框架,它的目的是处理服务器端的请求和响应。作为一个基于事件驱动的框架,Node.js的主要特点是可以在单个线程中同时处理多个请求,可以让服务器端以非阻塞式的方式高效响应。它使用JavaScript编写,因此对于前端开发人员来说,学习Node.js会很方便,但是需要注意其中的异步编程模式和事件驱动机制。

  1. 适用场景

ExtJS的主要应用场景是需要较高的用户交互性和优化的UI界面,例如CRM(客户关系管理)、ERP(企业资源计划)系统、管理仪表板等。ExtJS可以利用其大量提供的预定义组件来进行快速开发,并且可以方便地定制自己的界面视图和UI元素。

相对而言,Node.js的应用范围比较广泛,包括实时数据推送、多人在线游戏、即时通讯等等。如果应用程序需要非常短的响应时间和高并发处理能力,那么Node.js是一个非常适合的选择。Node.js的Web框架Express和Koa提供了许多功能,可以用于开发RESTful API、Web应用程序等,而且支持各种数据存储方式,包括非关系型数据库MongoDB。

  1. 开发流程

在使用ExtJS进行开发时,开发者需要按照MVC的规定进行代码组织和结构。这意味着开发者将应用程序的逻辑分成三个部分:模型(Model)、视图(View)、控制器(Controller)。这种分层能够使代码更加易于维护,同时也可以实现代码重用和配置灵活性。

在使用Node.js进行开发时,开发者需要使用异步编程技术来处理并发请求。Node.js中提供了许多异步API,例如回调函数、Promise和事件。开发者需要熟练掌握这些技术,才能写出高效的代码。此外,Node.js还支持模块化开发,开发者可以通过使用NPM(Node包管理器)来管理和共享Node.js模块,这在提高开发效率和代码质量方面都有很大的帮助。

  1. 语言语法

ExtJS和Node.js都基于JavaScript语言,但是它们的语法风格却有很大的不同。在Node.js中,由于异步编程的需要,开发者需要使用回调函数、Promise和事件来管理程序的流程。这使得Node.js代码更加复杂,并且需要更多的细心和调试注意力。

相比之下,ExtJS使用了一种更加直观和简单的方式来描述代码,这是因为它的主要任务是构建和管理界面,而且没有像Node.js那样需要处理高并发问题,因此更强调代码的可读性和可重用性。

总结

在一定程度上来说,ExtJS和Node.js这两种技术可以互相补充。ExtJS可以用于构建客户端界面,Node.js则可以用于处理服务器端。开发人员需要评估应用程序的需求,选择合适的技术方案,才能开发出高质量的应用程序。

以上就是extjs与nodejs的区别的详细内容,更多请关注php中文网其它相关文章!

JS与Node.js中的事件循环

JS与Node.js中的事件循环

这两天跟同事同事讨论遇到的一个问题,js中的event loop,引出了chrome与node中运行具有setTimeoutPromise的程序时候执行结果不一样的问题,从而引出了Nodejs的event loop机制,记录一下,感觉还是蛮有收获的

console.log(1)
setTimeout(function() {
  new Promise(function(resolve, reject) {
    console.log(2)
    resolve()
  })
      .then(() => {
        console.log(3)
      })
}, 0)

setTimeout(function() {
  console.log(4)
}, 0)

// chrome中运行:1 2 3 4
// Node中运行: 1 2 4 3

chrome和Node执行的结果不一样,这就很有意思了。

1. JS 中的任务队列

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

2. 任务队列 event loop

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
具体来说,异步执行的运行机制如下。(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。)

  1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  2. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  3. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  4. 主线程不断重复上面的第三步。

bg2014100801.jpg

只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。

3. 定时器 setTimeoutsetInterval

定时器功能主要由setTimeout()setInterval()这两个函数来完成,它们的内部运行机制完全一样,区别在于前者指定的代码是一次性执行,后者则为反复执行。
setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。
HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。对于那些DOM的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()
另外,浏览器内的计时器可能会因为很多原因而减慢速度:

  • CPU超载
  • 浏览器选项卡处于后台模式
  • 笔记本电脑使用电池

所有这些都可能将最小延迟提高到300ms甚至1000ms,具体取决于浏览器和设置。参考 Scheduling: setTimeout and setInterval
需要注意的是,setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

4. Nodejs特点

Nodejs架构

NodeJS的显著特点:异步机制事件驱动
事件轮询的整个过程没有阻塞新用户的连接,也不需要维护连接。基于这样的机制,理论上陆续有用户请求连接,NodeJS都可以进行响应,因此NodeJS能支持比Java、php程序更高的并发量。

虽然维护事件队列也需要成本,再由于NodeJS是单线程,事件队列越长,得到响应的时间就越长,并发量上去还是会力不从心。

RESTful API是NodeJS最理想的应用场景,可以处理数万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可。

5. Node.js的Event Loop

关于Nodejs中的事件循环还有另一篇文章详细探讨了下,可以参考阅读。

事件轮询主要是针对事件队列进行轮询,事件生产者将事件排队放入队列中,队列另外一端有一个线程称为事件消费者会不断查询队列中是否有事件,如果有事件,就立即会执行,为了防止执行过程中有堵塞操作影响当前线程读取队列,事件消费者线程会委托一个线程池专门执行这些堵塞操作。

时间轮询

Javascript前端和Node.js的机制类似这个事件轮询模型,有的人认为Node.js是单线程,也就是事件消费者是单线程不断轮询,如果有堵塞操作怎么办,不是堵塞了当前单线程的执行吗?
其实Node.js底层也有一个线程池,线程池专门用来执行各种堵塞操作,这样不会影响单线程这个主线程进行队列中事件轮询和一些任务执行,线程池操作完以后,又会作为事件生产者将操作结果放入同一个队列中。
总之,一个事件轮询Event Loop需要三个组件:

  1. 事件队列Event Queue,属于FIFO模型,一端推入事件数据,另外一端拉出事件数据,两端只通过这个队列通讯,属于一种异步的松耦合。
  2. 队列的读取轮询线程,事件的消费者,Event Loop的主角。
  3. 单独线程池Thread Pool,专门用来执行长任务,重任务,干繁重体力活的。

Node.js也是单线程的Event Loop,但是它的运行机制不同于浏览器环境。

Node.js结构

根据上图,Node.js的运行机制如下。

  1. V8引擎解析JavaScript脚本。
  2. 解析后的代码,调用Node API。
  3. libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。
  4. V8引擎再将结果返回给用户。

我们可以看到node.js的核心实际上是libuv这个库。这个库是c写的,它可以使用多线程技术,而我们的Javascript应用是单线程的。

Nodejs 的异步任务执行流程:

图片描述

用户写的代码是单线程的,但nodejs内部并不是单线程!

事件机制:
Node.js不是用多个线程为每个请求执行工作的,相反而是它把所有工作添加到一个事件队列中,然后有一个单独线程,来循环提取队列中的事件。事件循环线程抓取事件队列中最上面的条目,执行它,然后抓取下一个条目。当执行长期运行或有阻塞I/O的代码时,注意这里:它不会被阻塞,会继续提取下一个事件,而对于被阻塞的事件Node.js会从线程池中取出一个线程来运行这个被阻塞的代码,同时把当前事件本身和它的回调事件一同添加到事件队列(callback嵌套callback)。

在Node.js中,因为只有一个单线程不断地轮询队列中是否有事件,对于数据库文件系统等I/O操作,包括HTTP请求等等这些容易堵塞等待的操作,如果也是在这个单线程中实现,肯定会堵塞影响其他工作任务的执行,Javascript/Node.js会委托给底层的线程池执行,并会告诉线程池一个回调函数,这样单线程继续执行其他事情,当这些堵塞操作完成后,其结果与提供的回调函数一起再放入队列中,当单线程从队列中不断读取事件,读取到这些堵塞的操作结果后,会将这些操作结果作为回调函数的输入参数,然后激活运行回调函数。

请注意,Node.js的这个单线程不只是负责读取队列事件,还会执行运行回调函数,这是它区别于多线程模式的一个主要特点,多线程模式下,单线程只负责读取队列事件,不再做其他事情,会委托其他线程做其他事情,特别是多核的情况下,一个CPU核负责读取队列事件,一个CPU核负责执行激活的任务,这种方式最适合很耗费CPU计算的任务。反过来,Node..js的执行激活任务也就是回调函数中的任务还是在负责轮询的单线程中执行,这就注定了它不能执行CPU繁重的任务,比如JSON转换为其他数据格式等等,这些任务会影响事件轮询的效率。

6. 实例

看一个具体实例:

console.log(''1'')
setTimeout(function() {
  console.log(''2'')
  new Promise(function(resolve) {
    console.log(''4'')
    resolve()
  }).then(function() {
    console.log(''5'')
  })
  setTimeout(() => { console.log(''6'') })
  new Promise(function(resolve) {
    console.log(''7'')
    resolve()
  }).then(function() {
    console.log(''8'')
  })
})
setTimeout(function() {
  console.log(''9'')
}, 0)
new Promise(function(resolve) {
  console.log(''10'')
  resolve()
}).then(function() {
  console.log(''11'')
})
setTimeout(function() {
  console.log(''12'')
  new Promise(function(resolve) {
    console.log(''13'')
    resolve()
  }).then(function() {
    console.log(''14'')
  })
})
new Promise(function(resolve) {
  console.log(''15'')
  resolve()
}).then(function() {
  console.log(''16'')
})

// node1  : 1,10,15,11,16,2,4,7,9,12,13,5,8,14,6        // 结果不稳定
// node2  : 1,10,15,11,16,2,4,7,9,5,8,12,13,14,6        // 结果不稳定
// node3  : 1,10,15,11,16,2,4,7,5,8,9,12,13,14,6        // 结果不稳定
// chrome : 1,10,15,11,16,2,4,7,5,8,9,12,13,14,6

chrome的运行比较稳定,而node环境下运行不稳定,可能会出现两种情况。
chrome运行的结果的原因是Promiseprocess.nextTick()的微任务Event Queue运行的权限比普通宏任务Event Queue权限高,如果取事件队列中的事件的时候有微任务,就先执行微任务队列里的任务,除非该任务在下一轮的Event Loop中,微任务队列清空了之后再执行宏任务队列里的任务。

关于Node中的事件循环和异步API的内容,具体可以参见另一篇帖子,有具体讨论。

7. 浏览器中的事件循环

浏览器中和Node中的事件循环的执行顺序并不一致,在浏览器中,我们可以按性质把任务分为两类,macrotask(宏任务)和 microtask(微任务)。

  • macrotask: script (同步代码), setTimeout, setInterval, setImmediate, MessageChannel, postMessage, I/O, UI渲染
  • microtask: process.nextTick, Promises(这里指浏览器原生实现的 Promise), Object.observe, MutationObserver

clipboard.png

执行顺序:

  • 引擎首先从macrotask queue中取出第一个任务,执行完毕后,将microtask queue中的所有任务取出,按顺序全部执行;
  • 然后再从macrotask queue中取下一个,执行完毕后,再次将microtask queue中的全部取出;
  • 循环往复,直到两个queue中的任务都取完。

网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~

参考:

  1. Node.js的事件轮询Event Loop原理解释
  2. JavaScript 运行机制详解:再谈Event Loop
  3. js与Nodejs的单线程和异步--初探
  4. 这一次,彻底弄懂 JavaScript 执行机制
  5. JavaScript任务队列的顺序机制(事件循环)

PS:欢迎大家关注我的公众号【前端下午茶】,一起加油吧~

另外可以加入「前端下午茶交流群」微信群,长按识别下面二维码即可加我好友,备注加群,我拉你入群~

JS与Node.js中的事件循环详解

JS与Node.js中的事件循环详解

js中的event loop,引出了chrome与node中运行具有settimeout和promise的程序时候执行结果不一样的问题,从而引出了nodejs的event loop机制,本篇文章通过实例给大家详细分析了js与node.js中的事件的原理以及用法,希望能帮助到大家。

console.log(1)
setTimeout(function() {
 new Promise(function(resolve, reject) {
 console.log(2)
 resolve()
 })
 .then(() => {
 console.log(3)
 })
}, 0)
setTimeout(function() {
 console.log(4)
}, 0)
// chrome中运行:1 2 3 4
// Node中运行: 1 2 4 3
登录后复制

chrome和Node执行的结果不一样,这就很有意思了。

1. JS 中的任务队列

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

2. 任务队列 event loop

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

具体来说,异步执行的运行机制如下。(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。)

所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。主线程不断重复上面的第三步。

只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。

3. 定时器 setTimeout与setInterval

定时器功能主要由setTimeout()和setInterval()这两个函数来完成,它们的内部运行机制完全一样,区别在于前者指定的代码是一次性执行,后者则为反复执行。

setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。

HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。另外,对于那些DOM的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()。

需要注意的是,setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

4. Node.js的Event Loop

事件轮询主要是针对事件队列进行轮询,事件生产者将事件排队放入队列中,队列另外一端有一个线程称为事件消费者会不断查询队列中是否有事件,如果有事件,就立即会执行,为了防止执行过程中有堵塞操作影响当前线程读取队列,事件消费者线程会委托一个线程池专门执行这些堵塞操作。

Javascript前端和Node.js的机制类似这个事件轮询模型,有的人认为Node.js是单线程,也就是事件消费者是单线程不断轮询,如果有堵塞操作怎么办,不是堵塞了当前单线程的执行吗?

其实Node.js底层也有一个线程池,线程池专门用来执行各种堵塞操作,这样不会影响单线程这个主线程进行队列中事件轮询和一些任务执行,线程池操作完以后,又会作为事件生产者将操作结果放入同一个队列中。

总之,一个事件轮询Event Loop需要三个组件:

事件队列Event Queue,属于FIFO模型,一端推入事件数据,另外一端拉出事件数据,两端只通过这个队列通讯,属于一种异步的松耦合。队列的读取轮询线程,事件的消费者,Event Loop的主角。单独线程池Thread Pool,专门用来执行长任务,重任务,干繁重体力活的。

Node.js也是单线程的Event Loop,但是它的运行机制不同于浏览器环境。

根据上图,Node.js的运行机制如下。

V8引擎解析JavaScript脚本。解析后的代码,调用Node API。 libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。 V8引擎再将结果返回给用户。

我们可以看到node.js的核心实际上是libuv这个库。这个库是c写的,它可以使用多线程技术,而我们的Javascript应用是单线程的。

Nodejs 的异步任务执行流程:

用户写的代码是单线程的,但nodejs内部并不是单线程!

事件机制:

Node.js不是用多个线程为每个请求执行工作的,相反而是它把所有工作添加到一个事件队列中,然后有一个单独线程,来循环提取队列中的事件。事件循环线程抓取事件队列中最上面的条目,执行它,然后抓取下一个条目。当执行长期运行或有阻塞I/O的代码时

在Node.js中,因为只有一个单线程不断地轮询队列中是否有事件,对于数据库文件系统等I/O操作,包括HTTP请求等等这些容易堵塞等待的操作,如果也是在这个单线程中实现,肯定会堵塞影响其他工作任务的执行,Javascript/Node.js会委托给底层的线程池执行,并会告诉线程池一个回调函数,这样单线程继续执行其他事情,当这些堵塞操作完成后,其结果与提供的回调函数一起再放入队列中,当单线程从队列中不断读取事件,读取到这些堵塞的操作结果后,会将这些操作结果作为回调函数的输入参数,然后激活运行回调函数。

请注意,Node.js的这个单线程不只是负责读取队列事件,还会执行运行回调函数,这是它区别于多线程模式的一个主要特点,多线程模式下,单线程只负责读取队列事件,不再做其他事情,会委托其他线程做其他事情,特别是多核的情况下,一个CPU核负责读取队列事件,一个CPU核负责执行激活的任务,这种方式最适合很耗费CPU计算的任务。反过来,Node..js的执行激活任务也就是回调函数中的任务还是在负责轮询的单线程中执行,这就注定了它不能执行CPU繁重的任务,比如JSON转换为其他数据格式等等,这些任务会影响事件轮询的效率。

5. Nodejs特点

NodeJS的显著特点:异步机制、事件驱动。

事件轮询的整个过程没有阻塞新用户的连接,也不需要维护连接。基于这样的机制,理论上陆续有用户请求连接,NodeJS都可以进行响应,因此NodeJS能支持比Java、php程序更高的并发量。

虽然维护事件队列也需要成本,再由于NodeJS是单线程,事件队列越长,得到响应的时间就越长,并发量上去还是会力不从心。

RESTful API是NodeJS最理想的应用场景,可以处理数万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可。

6. 实例

看一个具体实例:

console.log('1')
setTimeout(function() {
 console.log('2')
 new Promise(function(resolve) {
 console.log('4')
 resolve()
 }).then(function() {
 console.log('5')
 })
 setTimeout(() => {
 console.log('haha')
 })
 new Promise(function(resolve) {
 console.log('6')
 resolve()
 }).then(function() {
 console.log('66')
 })
})
setTimeout(function() {
 console.log('hehe')
}, 0)
new Promise(function(resolve) {
 console.log('7')
 resolve()
}).then(function() {
 console.log('8')
})
setTimeout(function() {
 console.log('9')
 new Promise(function(resolve) {
 console.log('11')
 resolve()
 }).then(function() {
 console.log('12')
 })
})
new Promise(function(resolve) {
 console.log('13')
 resolve()
}).then(function() {
 console.log('14')
})
// node1 : 1,7,13,8,14,2,4,6,hehe,9,11,5,66,12,haha // 结果不稳定
// node2 : 1,7,13,8,14,2,4,6,hehe,5,66,9,11,12,haha // 结果不稳定
// node3 : 1,7,13,8,14,2,4,6,5,66,hehe,9,11,12,haha // 结果不稳定
// chrome : 1,7,13,8,14,2,4,6,5,66,hehe,9,11,12,haha
登录后复制

chrome的运行比较稳定,而node环境下运行不稳定,可能会出现两种情况。

chrome运行的结果的原因是Promise、process.nextTick()的微任务Event Queue运行的权限比普通宏任务Event Queue权限高,如果取事件队列中的事件的时候有微任务,就先执行微任务队列里的任务,除非该任务在下一轮的Event Loop中,微任务队列清空了之后再执行宏任务队列里的任务。

相关推荐:

Node.js事件循环教程

javascript事件循环之强制梳理

深入理解Node.js 事件循环和回调函数

以上就是JS与Node.js中的事件循环详解的详细内容,更多请关注php中文网其它相关文章!

js与nodejs的区别 ,http协议,

js与nodejs的区别 ,http协议,

学习的原网页网址:https://www.cnblogs.com/chenliyang/p/6558756.html

1.js,运行在浏览器上的,有各大浏览器的兼容性问题,

   解释型语言【程序运行才翻译,每次执行都翻译,效率低】

   编译性语言【通过编译器将程序翻译成二进制,要通过编译才能运行,只能在依托的平台上运行】有差别,

2.nodejs 运行在服务器上的js语言,不存在兼容性问题。

  express:第三方,安装好,直接引用,有路由和中间件构成的web框架。

  http2.0:简单的请求-响应协议,它通常运行在TCP之上。客户端给服务端发消息,服务端做响应。

  js与nodejs的相同点:都有自定义对象,宿主对象(bom ,dom),

3.http请求的理解:发送请求,返回数据的协议

  (1)通用信息,

  1.1 Request  URL  请求url

  1.2 request Method: 请求方法(get/post/put/delete/connect)

  1.3 Status Code:响应状态码 (200/301/302/400/404/500)

  (2)响应头信息

  2.1 Connection:keep-alive/close

  2.2 content-Type:文件类型

  2.3 transfer-Encoding:chunk(分段传输)【请求头会被拆分去不同的地方,拿到消息再合并起来传回来,故名分段请求】

  2.4 accept-encoding:接受压缩类型文件【gzip】

  (3)请求头信息

  3.1 accept:接受文件类型  html/text

  3.2 accept-encoding:接受压缩类型文件 gzip

  3.3 connection:连接方式 keep-alive

  3.4 user-agent: 用户代理浏览器

 

起因:htt协议无状态的协议

所以:Cookies:(本地机器一小段文本)【去一趟服务器,服务器就返给客户端,就有cookie】

   session: Session保存在服务器上,是针对每一个用户的,用一个sessionID来区分是哪个用户session变量, 【每个客户只要你来过服务端就存一个sessionID】

 

今天关于用好js与nodejs中的try...catchnodejs try catch的讲解已经结束,谢谢您的阅读,如果想了解更多关于extjs与nodejs的区别、JS与Node.js中的事件循环、JS与Node.js中的事件循环详解、js与nodejs的区别 ,http协议,的相关知识,请在本站搜索。

本文标签: