promise解决回调地狱(callback hell)

  • 具体参考 阮一峰,ES6标准入门
  • 在我们需要对一个异步操作进行频繁的调用的时候,且要保证一步操作的顺序,可能会出现
  • 回调地狱(callback)的情况 例如:
var fs = require('fs')fs.readFile('../data/a.txt','utf8',function (err,data) {if (err) {throw err}console.log(data)fs.readFile('../data/b.txt','utf8',function (err,data) {if (err) {throw err}console.log(data)fs.readFile('../data/c.txt','utf8',function (err,data) {if (err) {throw err}console.log(data);   }) })
})

解决这个问题让我们的代码看起来更加直观,我们可以用promise 解决这个问题

小栗子

var p1 = new Promise(function (resolve,reject) {fs.readFile('../data/a.txt','utf8',function (err,data) {if (err) {reject(err)} else {resolve(data)}})
})var p2 = new Promise(function (resolve,reject) {fs.readFile('../data/b.txt','utf8',function (err,data) {if (err) {reject(err)} else {resolve(data)}})
})var p3 = new Promise(function (resolve,reject) {fs.readFile('../data/c.txt','utf8',function (err,data) {if (err) {reject(err)} else {resolve(data)}})
})//console.log(p1)  //Promise { <pending> }p1.then(function (data) {console.log(data)//读取成功return p2 //把下一个要读取的promise返回},function (err) { //第二个参数表示读取失败 reject 拒绝了console.log(err+'p1失败');}).then(function (data) {console.log(data);return p2},function (err) {console.log(err+'p2失败');}).then(function (data) {console.log(data);},function (err) {console.log(err+'p3失败');})// 这样子就实现了promise 链式编程,但是重复的代码太多,//下面稍微改造一下封装一个方法
  • 但是这样子的代码复用太多,我们可以给他稍微封装一下
var fs = require('fs')function PreadFile (filePath) {return new Promise(function (resolve,reject) {fs.readFile(filePath,'utf8',function (err,data) {if (err) {reject(err)} else {resolve(data)}})})
}PreadFile('../data/a.txt').then(function (data) {console.log(data)return PreadFile('../data/b.txt')},function (err) {console.log(err+'a文件失败')}).then(function (data) {console.log(data)return PreadFile('../data/c.txt')},function (err) {console.log(err+'b文件失败')}).then(function (data) {console.log(data)},function (err) {console.log(err+'c文件失败')})

输出:a b c ,当然 这里的 function 用箭头函数代替更简洁,但涉及我书写blog的前后顺序和结构进性,在写es6前就尽量不使用es6语法糖

Promise.all和Promise.race

Promise.all

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
具体代码如下:

let p1 = new Promise((resolve, reject) => {resolve('成功了')
})let p2 = new Promise((resolve, reject) => {resolve('success')
})let p3 = Promse.reject('失败')Promise.all([p1, p2]).then((result) => {console.log(result)               //['成功了', 'success']
}).catch((error) => {console.log(error)
})Promise.all([p1,p3,p2]).then((result) => {console.log(result)
}).catch((error) => {console.log(error)      // 失败了,打出 '失败'
})

Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
代码模拟:

let wake = (time) => {return new Promise((resolve, reject) => {setTimeout(() => {resolve(`${time / 1000}秒后醒来`)}, time)})
}let p1 = wake(3000)
let p2 = wake(2000)Promise.all([p1, p2]).then((result) => {console.log(result)       // [ '3秒后醒来', '2秒后醒来' ]
}).catch((error) => {console.log(error)
})
  • 需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。

Promise.race

顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')},1000)
})let p2 = new Promise((resolve, reject) => {setTimeout(() => {reject('failed')}, 500)
})Promise.race([p1, p2]).then((result) => {console.log(result)
}).catch((error) => {console.log(error)  // 打开的是 'failed'
})

原理是挺简单的,但是在实际运用中还没有想到什么的使用场景会使用到。

总结

  • Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

  • 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

  • Promise对象有以下两个特点。

    • (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
    • (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
  • 注意,为了行文方便,本章后面的resolved统一只指fulfilled状态,不包含rejected状态。

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

  • Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
    如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署Promise更好的选择。

promise解决回调地狱(callback hell)相关推荐

  1. Promise(解决回调地狱)

    Promise() 对象: 存在三种状态: //进行时 pending// 成功 resolve//失败 reject 执行语句: let promise= new Promise((resolve, ...

  2. Promise的基础使用与生成器配合Promise解决回调地狱

    经过几天对Promise的了解,希望可以帮助到大家. 什么是回调地狱         说起回调地狱 首先想到的是异步 在js中我们经常会大量使用异步回调,常用的ajxa请求 来看下面这段代码: fun ...

  3. Promise解决回调地狱写法

    这里可以使用Promise来解决回调地狱的问题! 那么我们这里有一个需求,就是我们需要读取三个 .txt 文件,需要第一个文件读取完成后才能读取第二个文件以此类推. 那么这里来一个Promise的错误 ...

  4. promise解决回调地狱的问题

    什么是回调地狱 怎么解决回调地狱的问题 要了解什么是回调地狱,首先要了解 什么是同步,什么是异步函数 同步函数:当一个函数是同步执行时,那么当该函数被调用时不会立即返回,直到该函数要做的事情全部做完之 ...

  5. Promise解决回调地狱

    一.Promise是什么 Promise 其实是异步编程的一种解决方案.简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,可以从 ...

  6. node js Bluebird 简单介绍 promise 解决回调地狱

    Promise是异步代码实现控制流的一种方式.这一方式可以让你的代码干净.可读并且健壮. 异步回调如下: fs.readFile('directory/file-to-read', function( ...

  7. 使用promise解决回调地狱_「每日一题」Promise 是什么?

    window.Promise 已经是 JS 的一个内置对象了. 1. Promise 有规格文档吗? 2. 你一般如何使用 Promise. ----------- 目前的 Promise 都遵循 P ...

  8. 使用promise解决回调地狱_使用Promise 解决回调地狱

    const fs = require('fs') function getFileByPath(fpath) { return new Promise(function (resolve, rejec ...

  9. 使用promise解决回调地狱_回调地狱的由来和如何利用promise解决回调地狱

    var fs =require('fs') fs.readFile('./a.txt', 'utf8',function(err,data){ if(err){ console.log('读取失败') ...

最新文章

  1. MVC中,视图的Layout使用
  2. python中bind的用法_JS中的apply、call和bind的用法和区别
  3. java 常见数据类型
  4. 牛客网-斐波那契数列
  5. go语言游戏编程-Ebiten使用矩阵实现对图的缩放和移动
  6. 虚拟化服务器监控,监控服务器虚拟化软件
  7. 国王游戏(洛谷-P1080)
  8. 数据库事物用法 SET XACT_ABORT ON
  9. 10大国外IT网站(转)
  10. Apache Flink CDC 批流融合技术原理分析
  11. win10禁用驱动程序强制签名_如何将驱动程序注入Windows 10 WIM / ISO安装映像?
  12. java 回调函数传值_说明Java的传递与回调机制的代码示例分享
  13. 数据结构之八大排序算法(C语言实现)
  14. 霍纳法则c语言算法代码,霍纳法则(Horner's rule)
  15. Samsung-WLAN-AP路由器RCE漏洞复现
  16. ElasticSearch之别名_aliases
  17. 请注意!新办理的电话卡,有以下情况会导致“二次实名”!
  18. 10个顶级jQuery Date弹出插件
  19. L2-039 清点代码库(Python3)
  20. 【java感悟】接口,抽象类的关系

热门文章

  1. VSC | vscode 常用快捷键
  2. 沈阳城市学院计算机,喜讯:沈阳城市学院21个代表队在2019全国计算机大赛中全部获奖...
  3. kinit什么意思_kinit
  4. 华为nova3i 计算机在哪里,华为nova3i常见问题汇总,你想了解的都在这里
  5. matlab 在2k屏幕,如何将4k显示器的分辨率调整为2k,并将2k分辨率用于4k显示器
  6. MATLAB算法实战应用案例精讲-【人工智能】枝晶生长模型(附matlab代码实现)
  7. 酷派手机COOLPAD5380CA动态权限允许无法点击
  8. M_Map绘图笔记——快速入门(二)
  9. 《求职》第四部分 - 操作系统篇 - 操作系统基础
  10. 《Windows 8 权威指南》——2.4 Aero与Metro的触摸对比