Callback hell回调地域

当我们以同步的方式编写耗时的代码,那么就会阻塞JS的单线程,造成CPU一直等待IO完成才去执行后面的代码。

而CPU的执行速度是远远大于硬盘IO速度的,这样等待只会造成资源的浪费。

异步IO就是为了解决这个问题的,异步能尽可能不让CPU闲着,它不会在那等着IO完成;而是传递给底层的事件循环一个函数,自己去执行下面的代码。等磁盘IO完成后,函数就会被执行来作为通知。

虽然异步回调的编程方式能充分利用CPU,但是当代码逻辑变的越来越复杂后,新的问题出现了——Callback hell回调地域!

功能代码

实现如下功能:

  1. 判断一个文件是文件还是目录;
  2. 如果是目录,读取这个目录下的文件,找出结尾是txt的文件;
  3. 获取这些txt文件大小。

异步方式

function withoutPromise() {
    let target = "test";
    fs.stat(target, (err, stat)=>{
        if(err){
            throw err;
        }
        // 如果是文件夹
        if(stat.isDirectory()){
            fs.readdir(target, (err, files)=>{
                // 遍历files
                files.forEach( f =>{
                    if(path.extname(f) === '.txt'){
                        fs.stat(path.join(target, f), (err, stat)=>{
                            console.log(f+ " : "+stat.size);
                        });
                    }
                } );
            });
        }
    });
}

Promise方式

async function withPromise() {
    let target = "test";
    //将fs.stat转为一个可以返回Promise对象的方法
    let pstat = util.promisify(fs.stat);
    let stat = await pstat(target);
    // 如果是文件夹
    if(stat.isDirectory()){
        //将fs.readdir转为一个可以返回Promise对象的方法
        let preaddir = util.promisify(fs.readdir)
        let files = await preaddir(target)
        files.forEach( async (f) => {
            if(path.extname(f) === '.txt'){
                let stat = await pstat(path.join(target, f));
                console.log(stat.size);
            }
        });
    }
}

Promise和async/await

Promiseasync/await便是为了解决Callback hell的问题。

promise

promise的作用是对异步回调代码包装一下,把原来的一个回调函数拆成2个回调函数,这样的好处是可读性更好。语法如下:

// 创建promise对象
let promise = new Promise((resolve, reject)=>{
    // 在异步操作成功的情况选调用resolve,失败的时候调用reject
    fs.readFile('xxx.txt',(err, data)=>{
        if(err){
            reject(err)
        }else {
            resolve(data.toString())
        }
    })
});
// 使用promise
promise.then((text)=>{
    //then方法是当Promise内部调用了resolve的时候执行
}).catch((err)=>{
    //catch方法是当Promise内部调用了reject的时候执行
    console.log(err);
})
  • 语法注意:Promise内部的resolve和reject方法只能调用一次,调用了这个就不能再调用了那个;如果调用,则无效。

async/await

async/await的作用是直接将Promise异步代码变为同步的写法,注意,代码仍然是异步的

语法要求:

  • await只能用在async修饰的方法中,但是有async不要求一定有await
  • await后面只能跟async方法和promise

假设拥有了一个promise对象,现在使用async/await可以这样写:

async function asyncDemo() {
    try {
        // 当promise的then方法执行的时候
        let text = await promise
        // 当你用promise包装了所有的异步回调代码后,就可以一直await,真正意义实现了以同步的方式写异步代码
        console.log('异步道明执行');
    }catch (e){
        // 捕获到promise的catch方法的异常
        console.log(e);
    }
}
asyncDemo()
console.log('我是同步代码');

异步代码的终极写法

  1. 先使用promise包装异步回调代码,可使用node提供的util.promisify方法;
  2. 使用async/await编写异步代码。

参考

  • 黑马程序员 120天全栈区块链开发 开源教程

    https://github.com/itheima1/BlockChain

学习视频

一番同步了对应的学习视频到B站,长按识别可访问一番B站主页观看。

NodeJs-promise和async_await语法的更多相关文章

  1. Nodejs Promise的一点记录

    项目需要,看了点nodejs,其中比较难理解的就是Promise了,记录一下学习bluebird提供的Promise实现. Promise.promisifyAll(obj)方法 作用:把对象的方法属 ...

  2. 03-es6语法 Promise 和 es8语法 async await 的了解和基本使用

    //Promise // 1.说明 : Promise 是 es6 中提出的新语法 // 2.作用 : 用 '用户编写同步代码' 的方式 '处理异步' 的一种解决方案 // 3.以前 : 处理异步 , ...

  3. nodejs -Promise

    创建一个 readFile.js,读取三个文件abc的内容并输出到控制台 var fs = require('fs') fs.readFile('./a.txt','utf-8',function ( ...

  4. nodejs promise深度解析

    Promise本质上是一个容器,内部有一个执行函数,当promise对象New出来的时候,内部包裹的函数立即执行. V8引擎会将resolve和projeccted两个函数传递进来,resolved含 ...

  5. 【转载】游戏并发编程的讨论 & Nodejs并发性讨论 & 语法糖术语

    知乎上这篇文章对于游戏后端.性能并发.nodejs及scala等语言的讨论,很好,值得好好看. https://www.zhihu.com/question/21971645 经常了解一些牛逼技术人员 ...

  6. es6语法中promise的使用方法

    Promise是一个构造函数,它有resolve,reject,race等静态方法;它的原型(prototype)上有then,catch方法,因此只要作为Promise的实例,都可以共享并调用Pro ...

  7. Promise使用手册

    导读 Promise问世已久, 其科普类文章亦不计其数. 遂本篇初衷不为科普, 只为能够温故而知新. 比如说, catch能捕获所有的错误吗? 为什么有些时候会抛出"Uncaught (in ...

  8. Promise和Generator

    异同: 1.promise解决的是串行的嵌套异步问题. 2.yield把Generator Function切割为有多个出口的Generation. 3.Promise是社区的研发产物,yield是E ...

  9. 《深入理解ES6》笔记—— Promise与异步编程(11)

    为什么要异步编程 我们在写前端代码时,经常会对dom做事件处理操作,比如点击.激活焦点.失去焦点等:再比如我们用ajax请求数据,使用回调函数获取返回值.这些都属于异步编程. 也许你已经大概知道Jav ...

随机推荐

  1. mong 按 geometry 搜索 地理位置信息

    看 地理位置索引的使用 $near $geometry

  2. Exchange Server 2016 本地部署安装流程

    思路:一台Server 2016用作AD+DNS,一台Server 2016用作Exchange Server 2016 Exchange Server 2016 CU14 安装路径:安装路径:htt ...

  3. 如何从Serilog请求日志记录中排除健康检查终结点

    这是在ASP.NET Core 3.X中使用Serilog.AspNetCore系列文章的第四篇文章:. 第1部分-使用Serilog RequestLogging减少日志详细程度 第2部分-使用Se ...

  4. 最小环(floyd以及dijkstra实现+例题)

    最小环定义 最小环是指在一个图中,有n个节点构成的边权和最小的环(n>=3). 一般来说,最小环分为有向图最小环和无向图最小环. 最小环算法: 直接暴力: 设\(u\)和\(v\)之间有一条边长 ...

  5. 关于2D渲染的一些小想法

    原文地址 概述 . 这个项目最初的目的是为了尝试解析现有的UI编辑器(MyGUI)导出的UI布局信息,通过ImGUI还原UI渲染.但是在开发过程中,我发现可以借此实现一个编辑器,一个我不断的寻找,但始 ...

  6. python sqlalchemy mysql 自动映射

    SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作 简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果 ...

  7. 【大白话系列】MySQL 学习总结 之 初步了解 MySQL 的架构设计

    一.MySQL还是个黑盒子 我们都知道,只要我们系统引入了 MySQL 驱动和连接池,就能从数据库连接池获取一个数据库连接,然后就可以执行增删改查的操作了. 可是我们并不知道 MySQL 里面是怎么执 ...

  8. jmeter新手学习笔记(一)

    使用jmeter做接口测试--设置线程组 1.创建线程组 2.设置线程数配置信息 线程组:常用于模拟并发用户访问,例如需要100个用户访问该接口,线程数则设置为100 Ramp-Up Period:决 ...

  9. web开发发展历程

    cs架构:(软件主要运行在桌面上,数据库软件运行在服务器端) 缺点:如果web应用修改或升级,需要每个客户端逐个升级桌面App,因此Browser/server模式开始流行. bs架构:应用程序的逻辑 ...

  10. 详解python的装饰器decorator

    装饰器本质上是一个python函数,它可以让其它函数在不需要任何代码改动的情况下增加额外的功能. 装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志,性能测试,事务处理,缓存, ...