详解回调地狱以及promise
1.什么是回调地狱?
说promise之前必须先简单说下,回调地狱
回调地狱:在回调函数中又嵌套了多层回调函数,便会形成回调地狱
JS中或node中,都大量的使用了回调函数进行异步操作,而异步操作什么时候返回结果是不可控的,如果我们希望几个异步请求按照顺序来执行,那么就需要将这些异步操作嵌套起来,嵌套的层数特别多,就会形成回调地狱 或者叫做 横向金字塔。
例如我们创建一个文件夹,里面各自包含一句诗,要求这四个异步按顺序排列
如此大量使用回调函数,便会形成回调地狱
//第一步先导入fs模块
import { readFile } from 'fs'
readFile('./poetry/a.txt', 'utf-8', (err, data) => {console.log(data)readFile('./poetry/b.txt', 'utf-8', (err, data) => {console.log(data)readFile('./poetry/c.txt', 'utf-8', (err, data) => {console.log(data)readFile('./poetry/d.txt', 'utf-8', (err, data) => {console.log(data)})})})
})
为了解决回调地狱带来,代码难于维护和修改的弊端,ES6推出Promise对象来解决回调地狱
2.promise的基本概念
Promise对象是一个构造函数,用来生成Promise实例。是一种异步编程的解决方案,可以替换掉传统的回调函数解决方案。
类似一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法上说,Promise 是一个对象,使用的时候需要 new
而Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
实例中,它里面的异步操作就相当于一个承诺,而承诺就会有两种结果,要么完成了承诺的内容,要么失败。
Promise有 resolve(完成) 和 reject(失败) 两个形参
必须传入一个函数作为Promise的参数,这个函数在 new Promise的时候就会执行
将异步任务成功的结果传给 resolve 函数;将失败的信息传给 reject 函数
3.promise的基本用法(青铜)
//第一步先导入fs模块
import { readFile } from 'fs'
//第二步创建promise对象
const p1 = new Promise((resolve, reject) => {readFile('./poetry/a.txt', 'utf-8', (err, data) => {resolve(data) //暂不做判断,不考虑错误情况})
})
const p2 = new Promise((resolve, reject) => {readFile('./poetry/b.txt', 'utf-8', (err, data) => {resolve(data) //暂不做判断,不考虑错误情况})
})
const p3 = new Promise((resolve, reject) => {readFile('./poetry/c.txt', 'utf-8', (err, data) => {resolve(data) //暂不做判断,不考虑错误情况})
})
const p4 = new Promise((resolve, reject) => {readFile('./poetry/d.txt', 'utf-8', (err, data) => {resolve(data) //暂不做判断,不考虑错误情况})
})
//第三步读取文件
const a = p1.then(res => {console.log(res); //3.1 then()中的回调函数,不写返回值,默认返回一个空白的Promise对象,//3.2如果返回一个真实的Promise对象,那么就会赋值给 then()return p2 // 3.3返回一个 Promise 对象,调用下一个 then();
})
const b = a.then(res => {console.log(res);return p3
})
const c = b.then(res => {console.log(res);return p4
})
const d = c.then(res => {console.log(res)
})
4.promise的封装(黄金)
Promise 实例具有then方法,then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
//第一步导入fs模块
import { readFile } from 'fs'
//第二步封装一个方法.返回一个promise对象
function getpromise(url) {return new Promise((resolve, reject) => {readFile(url, 'utf-8', (err, data) => {resolve(data) //暂不做判断,不考虑错误情况})})
}
//调用
getpromise('./poetry/a.txt').then(res => {console.log(res);return getpromise('./poetry/b.txt')
}).then(res => {console.log(res);return getpromise('./poetry/c.txt')
}).then(res => {console.log(res);return getpromise('./poetry/d.txt')
}).then(res => console.log(res))
注意:then方法接收一个函数类型的参数,只处理成功
then方法接收两个函数类型的参数,分别用于接收 resolve 的值 和 reject 的值
then方法也可以只接收一个参数,表示只接收 resolve 的值,失败的结果可以通过链式调用catch方法捕获
5.promise的模块(钻石)
//需要先下载模块: npm i then-fs
// // 普通fs模块,readFile()返回 undefined ;
// // then-fs模块,readFile()返回 Promise 对象;
//先导入then-fs模块
import thenFs from 'then-fs'
// 读取文件
thenFs.readFile('./poetry/a.txt', 'utf8').then(res => {console.log(res);return thenFs.readFile('./poetry/b.txt', 'utf8');
}).then(res => {console.log(res);return thenFs.readFile('./poetry/c.txt', 'utf8');
}).then(res => {console.log(res);return thenFs.readFile('./poetry/d.txt', 'utf8');
}).then(res => console.log(res))
5.1Promise中的同步异步
Promise被创建的时候,执行的是同步代码;
new Promise 和 new 其他对象一样,是同步任务。
但是获取结果时(调用 resolve 触发 then方法时)是异步的。
// then()和catch()里面执行的是异步代码;
6.promise进阶(星耀)
ES2017 标准引入了 async 和 await,使得异步操作变得更加方便。
6.1 async函数
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
async 用于修饰一个 function
async 修饰的函数,总是返回一个 Promise 对象
函数内的所有值,将自动包装在 resolved 的 promise 中
async function fn() {return 666
}
let result = fn()
console.log(result) //Promise { 666 }
result.then(res => console.log(res)) //666
6.2 await命令
正常情况下await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
await只能出现在异步函数中!
await能停止代码执行,让后面的同步代码,先执行
await后面跟随的是一个promise对象
await返回的是: Promise对象中的then()中的回调函数中的参数res
async function fn() {return 666
}
console.log('嘻嘻') //第一个同步先执行async function fn2() {console.log('哈哈') //第二个同步 let str = await fn() // await会 暂停函数的执行 但不会影响同步console.log(str)console.log(888);
}
fn2()
console.log(333) //第三个同步
let result = fn()
6.3加入async和await
//先导入then-fs模块
import thenFs from "then-fs";
async function getpromise() {const a = await thenFs.readFile('./poetry/a.txt', 'utf8')const b = await thenFs.readFile('./poetry/b.txt', 'utf8')const c = await thenFs.readFile('./poetry/c.txt', 'utf8')const d = await thenFs.readFile('./poetry/d.txt', 'utf8')console.log(a)console.log(b)console.log(c)console.log(d)
}
getpromise()
7.promise解决回调地狱(王者)
await需要等待promise执行完毕,所以 await会 暂停函数的执行,但不会影响其他同步任务。
await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中
7.1promise三种状态
Promise对象代表一个异步操作,
有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
一旦状态改变,就不会再变
状态的改变只有两种可能:
从pending(进行中)变为fulfilled(已成功)
从pending(进行中)变为rejected(已失败)
当达到最终的 fulfilled 或 rejected 时,promise的状态就不会再改变了。
7.2Promise.prototype.finally()
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
下面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行
// 先导入then-fs
import thenFs from 'then-fs';
async function fn() {try {const str1 = await thenFs.readFile('./poetry/a.txt', 'utf8');console.log(str1);const str2 = await thenFs.readFile('./poetry/b.txt', 'utf8');console.log(str2);const str3 = await thenFs.readFile('./poetry/c.txt', 'utf8');console.log(str3);const str4 = await thenFs.readFile('./poetry/d.txt', 'utf8');console.log(str4);} catch (e) {console.log("文件读取错误: " + e.message);} finally {console.log('无论有没有错误都要执行的代码...');}
}
fn();
未完待续…
详解回调地狱以及promise相关推荐
- 【JavaScript】回调地狱、Promise
文章目录 1. 回调函数 2. 异步任务 3. 回调地狱 4. Promise 4.1 Promise定义 4.2 Promise基础用法 4.2.1 生成Promise实例 4.2.2 Promis ...
- ES6(三)——回调地狱和promise异步任务顺序执行(传参、错误处理)
文章目录 方法一.回调函数(回调地狱) 方法二:promise 2.1异步任务传参(单个) 2.2异步任务传参(多个) 2.3 错误处理 2.4 Promiss对象三大状态: (学名) 2.5 Pro ...
- 回调地狱终结者——Promise
在Web前端开发中,我们使用JavaScript会大量依赖异步计算.比如说,Ajax请求时,我们可能会需要不只一个请求来达到某种目的,此时需要后面的请求依赖于前面请求的结果.这种情况在简单的业务中并无 ...
- 回调地狱和Promise
目录 1.回调地狱callback-hell 由于fs.readFile是异步操作,所以你不能判断下面三个文件的执行顺序 var fs = require('fs')fs.readFile('./da ...
- 回调地狱与promise
<script src="js/ajax.js"></script><script>// function fn(a){// a()// }// ...
- 什么是回调地狱以及promise的链式调用和aysnc/await
上面一篇博客写到了回调地域的问题,这篇博客将深究这个词语,如下例: doSomething(function(result){doSomethingElse(result, function(newR ...
- python回调函数实例详解_python 简单的例子下详解回调函数
回调的英文定义: A callback is a function that is passed as an argument to another function and is executed ...
- Promise入门详解和基本用法 我来教你
JavaScript的执行环境是单线程. 所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任 ...
- [绍棠] Promise入门详解和基本用法
异步调用 异步 JavaScript的执行环境是单线程. 所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它 ...
最新文章
- php学习,一个简单的Calendar(2) 一个简单的活动页面
- Galaxy v-21.01 发布,新的流程和历史栏体验
- 原来益生菌是这么搞定致病菌的
- 重磅来袭!谷歌八年高级工程师亲授面试经验!!!
- 重大合同实为旧事 数据港信披被上交所问询
- mysql 线程内存 回收_MySQL内存使用-线程独享
- c++面试题【转】 面经
- CSS DIV 居中
- VS2013出现“无法找到“xxx.exe”的调试信息,或者调试信息不匹配”错误解决方案
- Google Guava BloomFilter
- REVERSE-PRACTICE-BUUCTF-5
- 文件服务器ping延时大,windowns 2008 ping 127.0.0.1延迟大的解决方法。
- spring helloworld
- 微信公众号开发C#系列-5、用户和用户组管理-支持同步
- Pytorch 基本概念
- 拓端tecdat|R语言使用二元回归将序数数据建模为多元GLM
- iOS 进阶 第二十二天(0603)
- 彼之蜜糖,我之砒霜;彼之敝履,吾之瑰宝
- js混淆还原工具_技术分享:几种常见的JavaScript混淆和反混淆工具分析实战【转】...
- Kali Linux全网最细安装教程
热门文章
- 踩坑:EasyExcel导出excel导出数据为空
- Principles for Microservice Design: Think IDEALS SOLID
- Lecture 1: Probability Models and Axioms
- 个人博客项目开发总结(一) 项目架构及后端开发
- 电动车行业上演“三国杀”,碳达峰压力下到底谁是老大?
- 鼠标经过箭头时,图片会向左或向右…
- 民工哥的十年故事:杭漂十年,今撤霸都!
- 网络规划中的IP地址分配
- Mockito教程一
- craco中使用px2rem,进行px转rem,解决分辨率适配问题