• 售前

  • 售后

热门帖子
入门百科

nodejs中的异步编程知识点详解

[复制链接]
无将大车 显示全部楼层 发表于 2021-10-25 19:03:25 |阅读模式 打印 上一主题 下一主题
简介


由于javascript默认环境下是单线程的,这意味着代码不能创建新的线程来并行实行。但是对于最开始在浏览器中运行的javascript来说,单线程的同步实行环境显然无法满足页面点击,鼠标移动这些相应用户的功能。于是浏览器实现了一组API,可以让javascript以回调的方式来异步相应页面的哀求事件。
更进一步,nodejs引入了非壅闭的 I/O ,从而将异步的概念扩展到了文件访问、网络调用等。
今天,我们将会深入的探讨一下各种异步编程的优缺点和发展趋势。
同步异步和壅闭非壅闭


在讨论nodejs的异步编程之前,让我们来讨论一个比力容易肴杂的概念,那就是同步,异步,壅闭和非壅闭。
所谓壅闭和非壅闭是指历程大概线程在举行操作大概数据读写的时间,是否必要等候,在等候的过程中可否举行其他的操作。
假如必要等候,并且等候过程中线程或历程无法举行其他操作,只能傻傻的等候,那么我们就说这个操作是壅闭的。
反之,假如历程大概线程在举行操作大概数据读写的过程中,还可以举行其他的操作,那么我们就说这个操作优劣壅闭的。
同步和异步,是指访问数据的方式,同步是指必要主动读取数据,这个读取过程大概是壅闭大概优劣壅闭的。而异步是指并不必要主动去读取数据,是被动的关照。
很显着,javascript中的回调是一个被动的关照,我们可以称之为异步调用。
javascript中的回调


javascript中的回调是异步编程的一个非常典范的例子:
  1. document.getElementById('button').addEventListener('click', () => {
  2. console.log('button clicked!');
  3. })
复制代码
上面的代码中,我们为button添加了一个click事件监听器,假如监听到了click事件,则会出发回调函数,输出相应的信息。
回调函数就是一个普通的函数,只不外它被作为参数通报给了addEventListener,并且只有事件触发的时间才会被调用。
上篇文章我们讲到的setTimeout和setInterval现实上都是异步的回调函数。
回调函数的错误处置惩罚


在nodejs中怎么处置惩罚回调的错误信息呢?nodejs采用了一个非常巧妙的办法,在nodejs中,任何回调函数中的第一个参数为错误对象,我们可以通过判断这个错误对象的存在与否,来举行相应的错误处置惩罚。
  1. fs.readFile('/文件.json', (err, data) => {
  2. if (err !== null) {
  3. //处理错误
  4. console.log(err)
  5. return
  6. }
  7. //没有错误,则处理数据。
  8. console.log(data)
  9. })
复制代码
回调地狱


javascript的回调固然非常的优秀,它有用的办理了同步处置惩罚的标题。但是遗憾的是,假如我们必要依赖回调函数的返回值来举行下一步的操作的时间,就会陷入这个回调地狱。
叫回调地狱有点夸张了,但是也是从一方面反映了回调函数所存在的标题。
  1. fs.readFile('/a.json', (err, data) => {
  2. if (err !== null) {
  3. fs.readFile('/b.json',(err,data) =>{
  4.   //callback inside callback
  5. })
  6. }
  7. })
复制代码
怎么办理呢?
别怕ES6引入了Promise,ES2017引入了Async/Await都可以办理这个标题。
ES6中的Promise


什么是Promise
Promise 是异步编程的一种办理方案,比传统的办理方案“回调函数和事件”更公道和更强大。
所谓Promise,简朴说就是一个容器,里面生存着某个未来才会竣事的事件(通常是一个异步操作)的结果。
从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
Promise的特点


Promise有两个特点:
1、对象的状态不受外界影响。
Promise对象代表一个异步操作,有三种状态:Pending(举行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
2、一旦状态改变,就不会再变,任何时间都可以得到这个结果。
Promise对象的状态改变,只有两种大概:从Pending变为Resolved和从Pending变为Rejected。
这与事件(Event)完全差别,事件的特点是,假如你错过了它,再去监听,是得不到结果的。
Promise的长处


      
  • Promise将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。  
  • Promise对象提供统一的接口,使得控制异步操作更加容易。
Promise的缺点


      
  • 无法取消Promise,一旦新建它就会立刻实行,无法中途取消。  
  • 假如不设置回调函数,Promise内部抛出的错误,不会反应到外部。  
  • 当处于Pending状态时,无法得知现在希望到哪一个阶段(刚刚开始还是即将完成)。
Promise的用法


Promise对象是一个构造函数,用来生成Promise实例:
  1. var promise = new Promise(function(resolve, reject) {
  2. // ... some code
  3. if (/* 异步操作成功 */){
  4. resolve(value);
  5. } else { reject(error); }
  6. }
  7. );
复制代码
promise可以接then操作,then操作可以接两个function参数,第一个function的参数就是构建Promise的时间resolve的value,第二个function的参数就是构建Promise的reject的error。
  1. promise.then(function(value) {
  2. // success
  3. }, function(error) {
  4. // failure }
  5. );
复制代码
我们看一个具体的例子:
  1. function timeout(ms){
  2. return new Promise(((resolve, reject) => {
  3.   setTimeout(resolve,ms,'done');
  4. }))
  5. }
  6. timeout(100).then(value => console.log(value));
复制代码
Promise中调用了一个setTimeout方法,并会定时触发resolve方法,并传入参数done。
最后程序输出done。
Promise的实行次序


Promise一经创建就会立马实行。但是Promise.then中的方法,则会比及一个调用周期过后再次调用,我们看下面的例子:
  1. let promise = new Promise(((resolve, reject) => {
  2. console.log('Step1');
  3. resolve();
  4. }));
  5. promise.then(() => {
  6. console.log('Step3');
  7. });
  8. console.log('Step2');
复制代码
输出
  1. Step1
  2. Step2
  3. Step3
复制代码
async和await


Promise当然很好,我们将回调地狱转换成了链式调用。我们用then来将多个Promise毗连起来,前一个promise resolve的结果是下一个promise中then的参数。
链式调用有什么缺点呢?
好比我们从一个promise中,resolve了一个值,我们必要根据这个值来举行一些业务逻辑的处置惩罚。
假如这个业务逻辑很长,我们就必要在下一个then中写很长的业务逻辑代码。如许让我们的代码看起来非常的冗余。
那么有没有什么办法可以直接返回promise中resolve的结果呢?
答案就是await。
当promise前面加上await的时间,调用的代码就会制止直到 promise 被办理或被拒绝。
留意await肯定要放在async函数中,我们来看一个async和await的例子:
  1. const logAsync = () => {
  2. return new Promise(resolve => {
  3. setTimeout(() => resolve('小马哥'), 5000)
  4. })
  5. }
复制代码
上面我们界说了一个logAsync函数,该函数返回一个Promise,由于该Promise内部利用了setTimeout来resolve,所以我们可以将其当作是异步的。
要是利用await得到resolve的值,我们必要将其放在一个async的函数中:
  1. const doSomething = async () => {
  2. const resolveValue = await logAsync();
  3. console.log(resolveValue);
  4. }
复制代码
async的实行次序


await现实上是去等候promise的resolve结果我们把上面的例子结合起来:
  1. const logAsync = () => { return new Promise(resolve => {  setTimeout(() => resolve('小马哥'), 1000) })}const doSomething = async () => {
  2. const resolveValue = await logAsync();
  3. console.log(resolveValue);
  4. }console.log('before')doSomething();console.log('after')
复制代码
上面的例子输出:
  1. before
  2. after
  3. 小马哥
复制代码
可以看到,aysnc是异步实行的,并且它的次序是在当前这个周期之后。
async的特点


async会让所有后面接的函数都酿成Promise,纵然后面的函数没有显示的返回Promise。
  1. const asyncReturn = async () => {
  2. return 'async return'
  3. }
  4. asyncReturn().then(console.log)
复制代码
由于只有Promise才能在后面接then,我们可以看出async将一个普通的函数封装成了一个Promise:
  1. const asyncReturn = async () => {
  2. return Promise.resolve('async return')
  3. }
  4. asyncReturn().then(console.log)
复制代码
总结


promise避免了回调地狱,它将callback inside callback改写成了then的链式调用情势。
但是链式调用并不方便阅读和调试。于是出现了async和await。
async和await将链式调用改成了类似程序次序实行的语法,从而更加方便理解和调试。
我们来看一个对比,先看下利用Promise的环境:
  1. const getUserInfo = () => {
  2. return fetch('/users.json') // 获取用户列表
  3. .then(response => response.json()) // 解析 JSON
  4. .then(users => users[0]) // 选择第一个用户
  5. .then(user => fetch(`/users/${user.name}`)) // 获取用户数据
  6. .then(userResponse => userResponse.json()) // 解析 JSON
  7. }
  8. getUserInfo()
复制代码
将其改写成async和await:
  1. const getUserInfo = async () => {
  2. const response = await fetch('/users.json') // 获取用户列表
  3. const users = await response.json() // 解析 JSON
  4. const user = users[0] // 选择第一个用户
  5. const userResponse = await fetch(`/users/${user.name}`) // 获取用户数据
  6. const userData = await userResponse.json() // 解析 JSON
  7. return userData
  8. }
  9. getUserInfo()
复制代码
可以看到业务逻辑变得更加清楚。同时,我们获取到了许多中间值,如许也方便我们举行调试。
到此这篇关于nodejs中的异步编程知识点详解的文章就先容到这了,更多干系深入理解nodejs中的异步编程内容请搜刮草根技术分享以前的文章或继续浏览下面的干系文章希望大家以后多多支持草根技术分享!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作