一、promise用来做什么?
异步编程的解决方案
解决回调地狱
1、回调地狱是什么?
看一个需求:依次去执行异步代码
//外边有三个文件,我们来依次读取
const fs = require('fs')
fs.readFile(`${__dirname}/etc/a.txt`,'utf-8', (err, data) =>{
if (err) {
console.log(err);
} else {
console.log(data);
}
fs.readFile(`${__dirname}/etc/b.txt`,'utf-8', (err, data) =>{
if (err) {
console.log(err);
} else {
console.log(data);
}
fs.readFile(`${__dirname}/etc/c.txt`,'utf-8', (err, data) =>{
if (err) {
console.log(err);
} else {
console.log(data);
}
这样读取的话会出现文件顺序的问题,所以:
fs.readFile(`${__dirname}/etc/a.txt`,'utf-8', (err, data) => {
if (err) {
console.log(err);
} else {
console.log(data);
fs.readFile(`${__dirname}/etc/b.txt`, 'utf-8', (err, data) => {
if (err) {
console.log(err);
} else {
console.log(data);
fs.readFile(`${__dirname}/etc/c.txt`, 'utf-8', (err, data) => {
if (err) {
console.log(err);
} else {
console.log(data);
}
})
}
})
}
})
这样就形成了回调地狱。
2、promise用来解决回调地狱
es6语法
- Promise对象是一个构造函数,用来生成Promise对象
- Promise构造函数接受一个函数作为参数
- 这个作为参数的函数,又有两个参数,这两参数分别是resolve跟reject
- 这两个参数也是函数,他们由javascript引擎提供,不用自己部署
- 异步操作成功后调用resolve()方法,他内部调用了then()里面的第一个参数函数
- 异步操作失败后调用reject()方法,他内部调用了then()里面的第二个参数函数
const fs = require('fs')
// 调用Promise构造函数,创建一个promise实例
let p = new Promise((resolve, reject) => {
// 写异步操作(读文件)
fs.readFile(`${__dirname}/etc/a.txt`, 'utf-8', (err, data) => {
if (!err) {
// 操作成功
resolve(data)
} else {
// 操作失败
reject(err)
}
})
})
p.then((data) => {
console.log(data)
}, (err) => {
console.log(err)
})
二、promise原理
promise 对象代表一个异步操作
有三种状态:pending进行中、fulfilled已成功、rejected已失败
- Promise对象的状态改变,只有两种可能:从pending变为fulfilled、从pending变为rejected
- 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
- 如果异步操作成功了,从pending变为fulfilled
- 如果异步操作失败了,从pending变为rejected
- 状态如果已经确定了,就不会在改变这个状态了
三、promise特点
- promise新建后就会立即执行,不要写其他无关代码
四、promise封装
const fs = require('fs')
function getPromise(filename) {
return new Promise((resolve, reject) => {
// 写异步操作(读文件)
fs.readFile(`${__dirname}/etc/${filename}.txt`, 'utf-8', (err, data) => {
if (!err) {
// 操作成功
resolve(data)
} else {
// 操作失败
reject(err)
}
})
})
}
getPromise().then((data) => {
console.log(data)
}, (err) => {
console.log(err)
})
四、解决回调地狱
让异步操作有顺序,并且无回调地狱
getPromise('a').then((data) => {
console.log(data)
// 调用函数得到一个读b文件的promise对象并返回
return getPromise('b')
}).then((data) => {
console.log(data)
// 调用函数得到一个读c文件的promise对象并返回
return getPromise('c')
}).then((data) => {
console.log(data)
})
五、promise的其他方法
1、catch方法
能够抓取错误
getPromise('a').then((data) => {
console.log(data)
// 调用函数得到一个读b文件的promise对象并返回
return getPromise('b')
}).then((data) => {
console.log(data)
// 调用函数得到一个读c文件的promise对象并返回
return getPromise('c')
}).then((data) => {
console.log(data)
}).catch((err)=>{
console.log(err)
})
2、all方法
用于将多个Promise实例,包装成一个新的Promise实例
一个都不能少
3、race方法
用于将多个Promise实例,包装成一个新的Promise实例
只要有一个promise执行成功,那这个就成功,相当于或者
六、ES6Module模块带来的好处
- 避免变量污染,命名冲突
- 提供代码的复用率、维护性
- 依赖关系管理
七、主要构成
1、export命令
用于规定模块对外的接口
- 外部能够读取模块内部的某个变量、函数、类
- 使用as关键字重命名
- 可以出现在模块的任何位置,只要处于模块顶层即可,除了块作用域内(import也一样)
2、import命令
用于输入其他模块提供的功能
- 变量、函数
- 使用as关键字
- 输入的变量都是只读的
- 具有提升效果
3、加载规则
浏览器加载ES6模块,也使用script标签
<script type='module'></script>
- 可以对变量取别名
- 导入的变量都是只读的,不能被修改
- 导入的对象属性是可以修改的
- 导入函数,存在变量提升效果
- 静态导入,不能使用表达式和变量运行时才能看到结果的代码