promise的优势
通过不同的方式读取在 files 文件夹下的三个文件来引出 promise 在处理异步时与回调函数相比的优势,files 文件夹有三个文件 a.json,b.json,c.json。
// a.json
{
"content": "this is a.json",
"next": "b.json"
}
// b.json
{
"content": "this is b.json",
"next": "c.json"
}
// c.json
{
"content": "this is c.json",
"next": null
}
现在要依次读取这三个文件,并且 b.json 的文件名要通过 a.json 文件中的 next 属性获得,c.json 的文件名要通过 b.json 的文件名获得。
首先我们先来看一下读取文件时输出内容的格式
const fs = require('fs')
const path = require('path')
// 回调函数且不封装为函数的方式
const fullFileName = path.resolve(__dirname, 'files', 'a.json')
fs.readFile(fullFileName, (err, data) => {
console.log(data)
})
从文件中直接读取出来的是二进制的形式
data 是二进制形式

data 转换为字符串
console.log(data.toString());

data 转换为对象
console.log(JSON.parse(data.toString());

现在我们用最符合人思维方式的写法来一次读取三个文件的内容。
// 回调函数且不封装为函数的方式
const fullFileName = path.resolve(__dirname, 'files', 'a.json')
// 读取a.json
fs.readFile(fullFileName, (err, data) => {
console.log(JSON.parse(data.toString()))
const fileName = JSON.parse(data.toString()).next
const fullFileName = path.resolve(__dirname, 'files', fileName)
// 从a.json中获得b.json文件名,然后读取b.json
fs.readFile(fullFileName, (err, data) => {
console.log(JSON.parse(data.toString()))
const fileName = JSON.parse(data.toString()).next
const fullFileName = path.resolve(__dirname, 'files', fileName)
// 从b.json中获取c.json文件名,然后读取c.json
fs.readFile(fullFileName, (err, data) => {
console.log(JSON.parse(data.toString()))
})
})
})
读取结果:

上面这样写代码复用性很低,我们可以考虑将读取文件内容封装为一个函数,这样每次读取文件内容时直接调用那个函数就可以了。
// 将读取文件内容封装成一个函数
function readFileContent(fileName) {
fs.readFile(fileName, (err, data) => {
console.log(JSON.parse(data.toString()))
})
}
// 读取a.json的内容
const fullFileName = path.resolve(__dirname, 'files', 'a.json')
readFileContent(fullFileName)
读取结果:

如果我们想要完成连续读取三个文件,并且下一个文件的文件名来自上一个文件,上面封装的函数显然是不能满足要求的。
上面回调函数的内容是 console.log(JSON.parse(data.toString())),这样写死的显然不能再读取下一个文件,如果我们将 readFileContent 的第二个参数变成一个函数,然后在回调函数中调用执行,那么在这个函数中我们就可以再次读取下一个文件。
// 封装连续读取文件的函数
function readFileContent(fileName, callback) {
const fullFileName = path.resolve(__dirname, 'files', fileName)
fs.readFile(fullFileName, (err, data) => {
// 这里使用callback时需要传递一个参数,那么定义的callback函数也有一个参数
callback(JSON.parse(data.toString()))
})
}
const fileName = 'a.json'
readFileContent(fileName, aData => {
console.log(aData);
// 获取b.json的名称
const fileName = aData.next;
// 读取b.json
readFileContent(fileName, bData => {
console.log(bData)
// 获取c.json的名称
const fileName = bData.next
// 读取c.json
readFileContent(fileName, cData => {
console.log(cData)
})
})
})
像上面这样写如果需要读取的文件继续增多,那么回调函数就会一直增加下去,呈现金字塔的形状,函数中间嵌套着函数,导致代码可读性较低,这也就是经常说的回调地狱。
关于回调地狱推荐这篇博文,讲的很清楚,回调地狱。
解决回调地狱一种比较常用的方法就是使用 promise,关于 promise 的知识在这里就不多说了,现在利用 promise 读取一个文件的内容。
const promise = new Promise((resolve, reject) => {
const fullFileName = path.resolve(__dirname, 'files', 'a.json');
fs.readFile(fullFileName, (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
promise.then((data) => {
console.log(JSON.parse(data.toString()))
}, (err) => {
console.log(err)
})
读取结果

这样写很显然不能完成多个文件的读取,我们现在也考虑将其封装为一个函数,如果让这个函数返回一个 promise 那么调用一次就返回一个 promise,这样就可以多次读取文件了。
// 封装函数利用promise读取三个文件的内容
function readFileContent(fileName) {
const fullFileName = path.resolve(__dirname, 'files', fileName)
return new Promise((resolve, reject) => {
fs.readFile(fullFileName, (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
const fileName = 'a.json'
readFileContent(fileName).then((data) => {
console.log(JSON.parse(data.toString()));
const fileName = JSON.parse(data.toString()).next;
return readFileContent(fileName)
}).then((data) => {
console.log(JSON.parse(data.toString()));
const fileName = JSON.parse(data.toString()).next;
return readFileContent(fileName)
}).then((data) => {
console.log(JSON.parse(data.toString()));
})
读取结果:

重点在于第19行和23行的代码,当在 then 中返回一个新的 promise 时,下一个 then 中的 data 就是这个新的 promise 中 resolve(data) 的参数 data,then 响应的是这个新的 promise。
可以看到当使用 promise 时,不会再出现函数嵌套的情况了,每个 then 都是一个异步操作,条理也比较清晰,因此 promise 也作为一种解决回调地狱比较常见的方式,解决回调地狱更多的方法可以参考上面推荐的那篇博客。
完,如有不恰当之处,还望告知,感谢。
promise的优势的更多相关文章
- 大白话讲解Promise(一)
去年6月份, ES2015正式发布(也就是ES6,ES6是它的乳名),其中Promise被列为正式规范.作为ES6中最重要的特性之一,我们有必要掌握并理解透彻.本文将由浅到深,讲解Promise的基本 ...
- Promise学习
转自:http://www.cnblogs.com/lvdabao/p/es6-promise-1.html 去年6月份, ES2015正式发布(也就是ES6,ES6是它的乳名),其中Promise被 ...
- 你不知道的JavaScript--大白话讲解Promise
转载:http://blog.csdn.net/i10630226/article/details/50867792 一.Promise小试 复杂的概念先不讲,我们先简单粗暴地把Promise用一下, ...
- JS 中Promise 模式
异步模式在web编程中变得越来越重要,对于web主流语言Javscript来说,这种模式实现起来不是很利索,为此,许多Javascript库(比如 jQuery和Dojo)添加了一种称为promise ...
- Es6 Promise 用法详解
Promise是什么?? 打印出来看看 console.dir(Promise) 这么一看就明白了,Promise是一个构造函数,自己身上有all.reject.resolve这几个眼熟的方 ...
- ES6 中 Promise 详解
Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可以获取异步操作的消息.Promise 提供统一的 API ...
- ES6中Promise详解
Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可以获取异步操作的消息. Promise 提供统一的 AP ...
- 【转】大白话讲解Promise(一)
原文地址:https://www.cnblogs.com/lvdabao/p/es6-promise-1.html ES6 Promise 先拉出来遛遛 复杂的概念先不讲,我们先简单粗暴地把Promi ...
- ES6 Promise 用法讲解
Promise是一个构造函数,自己身上有all.reject.resolve这几个眼熟的方法,原型上有then.catch等同样很眼熟的方法. 那就new一个 var p = new Promise( ...
随机推荐
- linux下大文件处理
linux下采用先分割后合并的策略处理大文件 第一步:分割文件 split split 参数:-a, --suffix-length=N 指定输出文件名的后缀,默认为2个-b, --bytes ...
- Spring aop(1)--- 寻找切面和代理对象执行流程源码分析
1.基于注解,首先我们是通过@EnableAspectJAutoProxy()这个注解开起AOP功能,这个注解会导入AspectJAutoProxyRegistrar组件从而将AnnotationAw ...
- 【简单版】hexo博客搭建流程梳理
前言 本文章会为你梳理一个搭建hexo博客的流程 相关网址: Docs: https://hexo.io/docs/ Themes: https://hexo.io/themes/ 安装hexo 准备 ...
- IP 转发分组的流程
IP 转发分组的流程 数据路由:路由器在不同网段转发数据包: 网络畅通的条件:数据包能去能回: 从源网络发出时,沿途的每一个路由器必须知道到目标网络下一跳给哪个接口: 从目标网络返回时,沿途的每一个路 ...
- 线程中断 interrupt 和 LockSupport
本文章将要介绍的内容有以下几点,读者朋友也可先自行思考一下相关问题: 线程中断 interrupt 方法怎么理解,意思就是线程中断了吗?那当前线程还能继续执行吗? 判断线程是否中断的方法有几个,它们之 ...
- 简单说 JavaScript中的事件委托(下)
说明 上次我们说了一些,关于 JavaScript中事件委托的 基础知识,这次我们继续来看. 解释 先来一段代码 <!doctype html> <html lang="e ...
- 【新功能】MaxCompoute禁止Full Scan功能开放
摘要: 2018年1月10日,MaxCompute禁止Full Scan功能开放.对于新创建的project默认情况下执行sql时,针对该project里的分区表不允许全表扫描,必须有分区条件指定需要 ...
- HTTP入门(一):在Bash中curl查看请求与响应
HTTP入门(一):在Bash中curl查看请求与响应 本文简单总结HTTP的请求与响应. 本文主要目的是对学习内容进行总结以及方便日后查阅. 详细教程和原理可以参考HTTP文档(MDN). 本文版权 ...
- DUBBO 面试灵魂18问
一.Dubbo 是什么 dubbo 是一个分布式框架,是一个远程服务调用的分布式框架,其核心部分包含: 1)集群容错: 提供基于接口方法的透明远程过程调用,包含多协议支持,以及软负债均衡.失败容错.地 ...
- 深入理解Java之线程池(网络笔记)
原文链接:http://www.cnblogs.com/dolphin0520/p/3932921.html 附加:http://www.cnblogs.com/wxd0108/p/5479442.h ...