回调地狱概念图: javascript
回调地狱:在咱们须要对一个异步操做进行频繁的调用的时候,且要保证一步操做的顺序,可能会出现.java
var fs=require('fs');
/* 注意这里的fs.readFile是一个异步任务,因此这里他们输出的顺序并非 按照代码的书写顺序,他们读取文件的输出顺序,跟文件资源的大小还有其余的元素有很大的关系 */
fs.readFile('./data/a.txt','utf8',function(err,data){
if(err){
/* 抛出异常 1.阻止程序的执行 2.把错误的消息打印到控制台 */
throw err
}
console.log(data);
});
fs.readFile('./data/b.txt','utf8',function(err,data){
if(err){
/* 抛出异常 1.阻止程序的执行 2.把错误的消息打印到控制台 */
throw err
}
console.log(data);
});
fs.readFile('./data/c.txt','utf8',function(err,data){
if(err){
/* 抛出异常 1.阻止程序的执行 2.把错误的消息打印到控制台 */
throw err
}
console.log(data);
});
复制代码
经过回调嵌套的方式保证顺序:ajax
var fs = require('fs');
/* 注意这里的fs.readFile是一个异步任务,因此这里他们输出的顺序并非 按照代码的书写顺序,他们读取文件的输出顺序,跟文件资源的大小还有其余的元素有很大的关系 */
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
/* 抛出异常 1.阻止程序的执行 2.把错误的消息打印到控制台 */
throw err
}
console.log(data);
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
/* 抛出异常 1.阻止程序的执行 2.把错误的消息打印到控制台 */
throw err
}
console.log(data);
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
/* 抛出异常 1.阻止程序的执行 2.把错误的消息打印到控制台 */
throw err
}
console.log(data);
});
});
});
复制代码
回调地狱的缺点: 1)代码的可维护性很是差,不利于代码的阅读 2)层层嵌套,代码复杂.promise
为了解决以上编码方式带来的问题(回调地狱嵌套),因此在ECMAScript 6 中新增了一个API:promise Promise的英文就是承诺 保证的意思bash
概念 : Promise是ES6中的新语法,Promise是一个构造函数,每一个new 出来的Promis实例对象都表明一个异步操做.异步
注意:使用promise并不会减小代码量
复制代码
简单建立:async
// Promise是构造函数
// Promise.prototype上有.then() .catch .finally(),由于他绑定到了原型上,因此根据原型链的查找规则,他的实例对象也可使用这个方法
// Promise表示异步操做
// 下面的这个代码表示建立了一个形式上的异步操做
// 经过new Promise()的时候,提供了一个function函数,在function函数中,能够执行具体的异步操做
const p=new Promise(function(){
// 在这个function中能够执行具体的异步操做
// 好比读文件,或发送ajax
// fs.readFile()
})
复制代码
.then方法的使用:函数
const fs=require('fs');
// 在ES6中新增了一个API Promise
// Promise 是一个构造函数
// 建立promise容器
// 1.给别人一个承诺
// Promise容器一旦建立,就开始执行里面的代码,
// 承诺自己不是异步的,可是内部每每都是封装一个异步任务
var p1=new Promise(function(resolve,rejected){
fs.readFile('./data/a.txt','utf8',function(err,data){
if(err){
// 失败了,承诺容器中的任务失败了
// console.log(err);
// 把容器的Pending状态改变为Rejected
//调用reject就至关于调用了then方法的第二个参数
rejected(err);
}else{
// 承诺容器中的任务成功了
// console.log(data);
// 把容器的Pending状态改成Resolved
// 也就是说这里调用的resolve方法实际上就是then方法传递的function
resolve(data);
}
});
});
// p1就是那个承诺
// 当p1成功了而后(then)作指定的操做
// then方法接收的function就是容器中的resolve
p1.then(function(data){
console.log(data);
},function(err){
console.log('读取文件失败了...',err);
})
复制代码
const fs = require('fs');
function pReadFile(filePath){
return new Promise(function (resolve, rejected) {
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
rejected(err);
} else {
resolve(data);
}
});
});
}
pReadFile('./data/a.txt')
.then(function(data){
console.log(data);
return pReadFile('./data/b.txt');
})
.then(function(data){
console.log(data);
return pReadFile('./data/c.txt');
})
.then(function(data){
console.log(data);
})
//能够经过.catch方法,捕获前面全部的.then方法发生的错误,几种处理
.catch(function(err){
console.log(err.message)
})
复制代码
Promise代码图示:优化
形式上,Generator 函数是一个普通函数,可是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不一样的内部状态(yield在英语里的意思就是“产出”) ES7 中的 async 和 await 能够简化 Promise 调用,提升 Promise 代码的 阅读性 和 理解性;ui
// 若是某个方法内部用到了await关键字,那么这个方法必须被修饰为异步async方法
// await只能用在被async修饰的方法中
async function test(){
// 若是某个方法的返回值是Promise的实例对象,就能够用await修饰Promise实例
// await只能用在被async修饰的方法中
const data=await getContentPath('./files/1.txt').catch(err=>err);
if(data instanceof Error){
console.log('文件读取失败')
}else{
console.log(data);
}
console.log(data);
const data2=await getContentPath('./files/2.txt');
console.log(data2);
const data3=await getContentPath('./files/3.txt');
console.log(data3);
}
// 这是异步方法,可是并非纯粹的异步方法
// 在异步方法中,遇到第一个await以前,全部的代码都是同步执行的
test();
复制代码
注意:async和await通常是同步使用的,二者缺一不可,
复制代码