返回顶部
首页 > 资讯 > 前端开发 > VUE >nodejs的关键节点有哪些
  • 551
分享到

nodejs的关键节点有哪些

2024-04-02 19:04:59 551人浏览 八月长安
摘要

本文小编为大家详细介绍“nodejs的关键节点有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs的关键节点有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。非阻

本文小编为大家详细介绍“nodejs的关键节点有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs的关键节点有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

非阻塞I/O

I/O:即 Input / Output,一个系统的输入和输出。

一个系统可以理解为一个个体,比如说一个人,你说话就是输出,你听就是输入。

阻塞 I/O 与非阻塞 I/O 的区别就在于系统接收输入再到输出期间,能不能接收其他输入

下面以两个例子来说明什么是阻塞 I/O 和非阻塞 I/O:

1、打饭

nodejs的关键节点有哪些

首先我们要确定一个系统的范围,在这个例子中食堂阿姨和餐厅的服务生看成是一个系统,输入就是点菜,输出就是端菜

那么在点菜和端菜之间能不能接受其他人的点菜,就可以判断是阻塞I/O还是非阻塞I/O。

对于食堂阿姨,他在点菜的时候,是不能帮其他同学点菜的,只有这个同学点完菜端菜走了之后,才能接受下一个同学的点菜,所以食堂阿姨是阻塞I/O。

对于餐厅服务员,他可以在点完菜以后,这个客人端菜之前是可以服务下一位客人的,所以服务员是非阻塞I/O。

2、做家务

nodejs的关键节点有哪些

在洗衣服的时候,是不需要等着洗衣机旁边的,这个时候可以去扫地和整理书桌,当整理完书桌后衣服也洗好了,这个时候去晾衣服,那么总共只需要25分钟。

洗衣服其实就是一个非阻塞I/O,在把衣服扔进洗衣机和洗完衣服期间,你是可以干其他事情的。

非阻塞I/O之所以能提升性能,是因为它可以把不必要的等待给节省掉。

理解非阻塞I/O的要点在于

  • 确定一个进行I/O的系统边界。这非常关键,如果把系统扩大,上面餐厅的例子,如果把系统扩大到整个餐厅,那么厨师肯定是一个阻塞 I/O。

  • 在 I/O 过程中,能不能进行其他 I/O。

nodejs的非阻塞 I/O

nodejs的非阻塞 I/O 是怎么体现的呢?前面说过理解非阻塞 I/O 的一个重要点是先确定一个系统边界,node的系统边界就是主线程

如果下面的架构图按照线程的维护划分,左边虚线部分是nodejs线程,右边虚线部分是c++线程。

nodejs的关键节点有哪些

现在 nodejs 线程需要去查询数据库,这是一个典型的 I/O 操作,它不会等待 I/O 的结果,而且继续处理其他的操作,它会把大量的计算能力分发到其他的c++线程去计算。

等到结果出来后返回给nodejs线程,在获得结果之前nodejs 线程还能进行其他的I/O操作,所以是非阻塞的。

nodejs 线程 相当于左边部分是服务员,c++ 线程是厨师。

所以,node的非阻塞I/O是通过调用c++的worker threads来完成的。

那当 c++ 线程获取结果后怎么通知 nodejs 线程呢?答案是事件驱动

事件驱动

阻塞:I/O时进程休眠,等待I/O完成后进行下一步;

非阻塞:I/O时函数立即返回,进程不等待I/O完成。

那怎么知道返回的结果,就需要用到事件驱动

所谓事件驱动可以理解为跟前端点击事件一样,我首先写一个点击事件,但是我不知道什么时候触发,只有触发的时候就去让主线程执行事件驱动函数。

这种模式也是一种观察者模式,就是我首先先监听这个事件,等触发时我就去执行。

那怎么实现事件驱动呢?答案是异步编程

异步编程

上面说过nodejs有大量的非阻塞I/O,那么非阻塞I/O的结果是需要通过回调函数来获取的,这种通过回调函数的方式,就是异步编程。比如下面的代码是通过回调函数获取结果的:

glob(__dirname+'*', (err, res) => {
    result = res
    console.log('get result')
})

回调函数格式规范

nodejs的回调函数第一个参数是error,后面的参数才是结果。为什么要这么做呢?

try {
  interview(function () {
       console.log('smile')
  })
} catch(err) {
    console.log('cry', err)
}

function interview(callback) {
    setTimeout(() => {
        if(Math.random() < 0.1) {
            callback('success')
        } else {
            throw new Error('fail')
        }
    }, 500)
}

执行之后,没有被捕获,错误被扔到了全局,导致整个nodejs程序崩溃了。

nodejs的关键节点有哪些

没有被try catch捕获是因为setTimeout重新开启了事件循环,每开启一个事件循环就重新生一个调用栈context,try catch是属于上一个事件循环的调用栈的,setTimeout的回调函数执行的时候,调用栈都不一样了,在这个新的调用栈中是没有try catch,所以这个错误被扔到全局,无法捕获。

那么怎么办呢?把错误也作为一个参数:

function interview(callback) {
    setTimeout(() => {
        if(Math.random() < 0.5) {
            callback('success')
        } else {
            callback(new Error('fail'))
        }
    }, 500)
}

interview(function (res) {
    if (res instanceof Error) {
        console.log('cry')
        return
    } 
    console.log('smile')
})

但是这样就比较麻烦,在回调中还要判断,所以就产生一种约定成熟的规定,第一个参数是err,如果不存在表示执行成功。

function interview(callback) {
    setTimeout(() => {
        if(Math.random() < 0.5) {
            callback(null, 'success')
        } else {
            callback(new Error('fail'))
        }
    }, 500)
}

interview(function (res) {
    if (res) {
        return
    } 
    console.log('smile')
})

异步流程控制

nodejs的回调写法,不仅会带来回调地域,还会带来异步流程控制的问题。

异步流程控制主要是指当并发的时候,怎么来处理并发的逻辑。还是上面的例子,如果你同事面试两家公司,只有当成功面试两家的时候,才可以不面试第三家,那么怎么写这个逻辑呢?需要全局顶一个一个变量count:

var count = 0
interview((err) => {
    if (err) {
        return
    }
    count++
    if (count >= 2) {
        // 处理逻辑
    }
})

interview((err) => {
    if (err) {
        return
    }
    count++
    if (count >= 2) {
        // 处理逻辑
    }
})

像上面这种写法就非常麻烦,且难看。所以,后来就出现了promise,async/await的写法。

promise

当前事件循环得不到的结果,但未来的事件循环会给你结果。很像一个渣男说的话。

promise不仅是一个渣男,还是一个状态机:

  • pending

  • fulfilled/resolved

  • rejectd

const pro = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('2')
    }, 200)
})
console.log(pro) // 打印:Promise { <pending> }
then & .catch
  • resolved 状态的 promise 会调用后面的第一个 then

  • rejected 状态的 promise 会调用后面的第一个 catch

  • 任何一个 reject 状态且后面没有 .catch 的 promise,都会造成浏览器或者 node 环境的全局错误。uncaught 表示未捕获的错误。

nodejs的关键节点有哪些

执行then或者catch会返回一个新的promise,该promise最终状态根据then和catch的回调函数的执行结果决定:

  • 如果回调函数始终是throw new Error,该promise是rejected状态

  • 如果回调函数始终是return,该promise是resolved状态

  • 但如果回调函数始终是return一个promise,该promise会和回调函数return的promise状态保持一致

function interview() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() > 0.5) {
                resolve('success')
            } else {
                reject(new Error('fail'))
            }
        })
    })
}

var promise = interview()
var promise1 = promise.then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('accept')
        }, 400)
    })
})

promise1的状态是由return里面的promise的状态决定的,也就是return里面的promise执行完后的状态就是promise1的状态。这样有什么好处呢?这样可以解决回调地狱的问题

var promise = interview()
    .then(() => {
        return interview()
    })
    .then(() => {
        return interview()
    })
    .then(() => {
        return interview()
    })
    .catch(e => {
        console.log(e)
    })

then如果返回的promise的状态是rejected,那么会调用后面第一个catch,后面的then就不会在调用了。记住:rejected调用后面的第一个catch,resolved调用后面的第一个then。

promise解决异步流程控制

如果promise仅仅是为了解决地狱回调,太小看promise了,promise最主要的作用是解决异步流程控制问题。下面如果要同时面试两家公司:

function interview() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() > 0.5) {
                resolve('success')
            } else {
                reject(new Error('fail'))
            }
        })
    })
}

promise
    .all([interview(), interview()])
    .then(() => {
        console.log('smile')
    })
    // 如果有一家公司rejected,就catch
    .catch(() => {
        console.log('cry')
    })

async/await

sync/await到底是什么:

console.log(async function() {
    return 4
})

console.log(function() {
    return new Promise((resolve, reject) => {
        resolve(4)
    })
})

打印的结果一样,也就是async/await是promse的语法糖而已。

我们知道try catch捕获错误是依赖调用栈的,只能捕获到调用栈以上的错误。但是如果使用await后能捕捉到调用栈所有函数的错误。即便这个错误是在另一个事件循环的调用栈抛出的,比如setTimeout。

改造面试代码,可以看到代码精简了很多。

try {
    await interview(1)
    await interview(2)
    await interview(2)
} catch(e => {
    console.log(e)
})

如果是并行任务呢?

await Promise.all([interview(1), interview(2)])

事件循环

因为nodejs的非阻塞 I/0, 所以需要利用事件驱动的方式获取 I/O 的结果,实现事件驱动拿到结果必须使用异步编程,比如回调函数。那么如何来有序的执行这些回调函数来获取结果呢?那就需要使用事件循环。

事件循环是实现 nodejs 非阻塞 I/O 功能的关键基础,非阻塞I/O和事件循环都是属于 libuv 这个c++库提供的能力。

nodejs的关键节点有哪些

代码演示:

const eventloop = {
    queue: [],
    loop() {
        while(this.queue.length) {
            const callback = this.queue.shift()
            callback()
        }
        setTimeout(this.loop.bind(this), 50)
    },
    add(callback) {
        this.queue.push(callback)
    }
}

eventloop.loop()

setTimeout(() => {
    eventloop.add(() => {
        console.log('1')
    })
}, 500)

setTimeout(() => {
	eventloop.add(() => {
		console.log('2')
	})
}, 800)

setTimeout(this.loop.bind(this), 50)保证了50ms就会去看队列中是否有回调,如果有就去执行。这样就形成了一个事件循环。

当然实际的事件要复杂的多,队列也不止一个,比如有一个文件操作对列,一个时间对列。

const eventloop = {
    queue: [],
    fsQueue: [],
    timerQueue: [],
    loop() {
        while(this.queue.length) {
            const callback = this.queue.shift()
            callback()
        }
        this.fsQueue.forEach(callback => {
            if (done) {
                callback()
            }
        })
        setTimeout(this.loop.bind(this), 50)
    },
    add(callback) {
        this.queue.push(callback)
    }
}

读到这里,这篇“nodejs的关键节点有哪些”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网VUE频道。

--结束END--

本文标题: nodejs的关键节点有哪些

本文链接: https://lsjlt.com/news/98822.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • nodejs的关键节点有哪些
    本文小编为大家详细介绍“nodejs的关键节点有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs的关键节点有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。非阻...
    99+
    2024-04-02
  • final关键字的小细节有哪些
    本篇内容主要讲解“final关键字的小细节有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“final关键字的小细节有哪些”吧!正文final关键字是一个常用的关键字,可以修饰变量、方法、类,...
    99+
    2023-06-15
  • 整理几个关键节点深入理解nodejs
    目录前言非阻塞I/Onodejs的非阻塞 I/O事件驱动异步编程回调函数格式规范异步流程控制promisethen & .catchpromise解决异步流程控制async/...
    99+
    2024-04-02
  • 写软文的关键点有哪些
    本篇内容介绍了“写软文的关键点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、明确中心思想,列好提纲理清思路。列提纲的意义有两个:一...
    99+
    2023-06-10
  • nodejs有哪些优点
    这篇文章主要讲解了“nodejs有哪些优点”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“nodejs有哪些优点”吧! nodej...
    99+
    2024-04-02
  • 关于主键的知识点有哪些
    本篇内容介绍了“关于主键的知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. UUID模式通用...
    99+
    2024-04-02
  • Java中关键字的知识点有哪些
    本文小编为大家详细介绍“Java中关键字的知识点有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java中关键字的知识点有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。...
    99+
    2024-04-02
  • 小程序的SEO优化关键点有哪些
    本篇内容介绍了“小程序的SEO优化关键点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!微信新发布小程序seo搜索优化指南,推出新的小程...
    99+
    2023-06-27
  • Redis的集群模式有哪些关键特点
    Redis集群模式的关键特点包括: 数据分片:Redis集群将数据分散存储在多个节点上,每个节点负责存储部分数据,通过数据分片实...
    99+
    2024-04-09
    Redis
  • nodejs与swoole的不同点有哪些
    这篇“nodejs与swoole的不同点有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“nodejs与swoole的不同...
    99+
    2023-06-29
  • vue的关键字有哪些
    vue中的关键字有:1.v-model,将标签的value值与vue实例中的data属性值进行绑定;2.v-on,通过配合具体的事件名来绑定Vue中定义的函数;3.v-bind,动态地绑定一个或多个特性;vue中的关键字有以下几种v-mod...
    99+
    2024-04-02
  • java的关键字有哪些
    java中常用的关键字有:1.abstract,用于修饰类和方法;2.boolean,用于声明布尔类型;3.class,用于声明一个类;4.return,用于表示一个方法返回的值;5.assert,用于创建一个断言;6.super,表明当前...
    99+
    2024-04-02
  • JavaScript有哪些关键字
    这篇文章主要为大家展示了“JavaScript有哪些关键字”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JavaScript有哪些关键字”这篇文章吧。JavaS...
    99+
    2024-04-02
  • mysql中的键和索引相关知识点有哪些
    本篇内容介绍了“mysql中的键和索引相关知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、主...
    99+
    2024-04-02
  • mysql外键的关系有哪些
    mysql外键的关系有哪些,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。  多对一  create table press( ...
    99+
    2024-04-02
  • javascript中的关键字有哪些
    javascript中的关键字有:1.break,立即退出循环;2.continue,退出当前循环;3.return,返回参数并停止函数;4.function,构造函数和定义函数直接量;5.with,引用对象;6.var,声明变量;7.th...
    99+
    2024-04-02
  • C#中的关键字有哪些
    这篇文章主要讲解了“C#中的关键字有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#中的关键字有哪些”吧!C# 关键字关键字是 C# 编译器预定义的保留字。这些关键字不能用作标识符,但...
    99+
    2023-06-17
  • Java的关键特性有哪些
    本篇内容主要讲解“Java的关键特性有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java的关键特性有哪些”吧!Document the Java: Sun Microsystems 公司...
    99+
    2023-06-03
  • jquery有哪些读取节点的方法
    本篇内容介绍了“jquery有哪些读取节点的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
    99+
    2024-04-02
  • Java字节码的知识点有哪些
    这篇文章主要为大家展示了“Java字节码的知识点有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java字节码的知识点有哪些”这篇文章吧。编译“1+1”代码首先我们需要写个简单的小程序,1+...
    99+
    2023-06-02
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作