😄高级农民工技术指南之JS异步编程-Promise对象
}
}
}
}
}
}
当你要重构一个项目的时候,兴高采烈的打开编辑器,然后发现代码是上面这样…
没错,这就是回调地狱,土话叫callback hell
。
不管是什么代码,只要大括号的嵌套超过三层,都会严重影响代码的可读性,人形编辑器出门右拐,当我没说过这话。
这样的代码对于开发人员来讲,就是灾难,这里你可能会说,就六七层嵌套,仔细看看就懂了,也不是什么难事。
这样呢?
不够过瘾?
类似这样金字塔形代码,我们统称为回调地狱。
日常开发中可能经常会遇到这样的问题:假如我们有很多(异步事件)函数,而这些(异步事件)函数之间又有很紧密的联系,比如一个(异步事件)函数要依赖另一个(异步事件)函数的返回值,这时你会怎么写?
//以前端常见的ajax async默认为true
//为了简洁这里用的全部是jQ中封装的ajax方法
$.ajax({
url: 'www.pronhub.com',
data: {},
type: 'post',
dataType: JSON,
success: function (res) {
$.ajax({
url: 'www.pronhub.com',
data: res.data,
type: 'post',
dataType: JSON,
success: function (res1) {
$.ajax({
url: 'www.pronhub.com',
data: res1.data,
type: 'post',
dataType: JSON,
success: function (res2) {
$.ajax({
url: 'www.pronhub.com',
data: res2.data,
type: 'post',
dataType: JSON,
success: function (res3) {
console.log(res3)
}
})
}
})
}
})
}
})
先不要关心我为什么会给pxxxhub发那么多post请求(我选的)
从上面的代码可以看出,请求成功后的回调函数,是另一个请求,并且函数形参部分是上一个请求的response。这就会引发一个问题,如果逻辑再复杂一点,就会一直…
而且在NodeJS出现以后,对于异步的依赖进一步加剧。
众所周知,在Node出生前Java、PHP、python等后台语言已经很成熟了,那么Node想要生存就必须有自己独到的优势。
无阻塞高并发都是Node的招牌,但是这些功能的实现,异步是基本的保障。
Promise用法详解
状态
- promise三种状态
- pending初始状态进行中
- resolved(fulfilled)操作成功
- rejected操作失败
- 只有异步操作的结果可以决定当前状态
- 状态一但成功/失败,任何其它操作都无法改变这个状态(这就是为啥叫promise)
基本API
Promise.resolve( )
Promise.reject( )
Promise.prototype.then( )
Promise.prototype.catch( )
Promise.all( )
Promsie.race( )
以上为Promise的API,开发中常用的是前四个.resolve()
、.reject()
、.then()
、.catch()
。记住这几个就没问题了。
.catch()
是用来捕捉错误的,前提是 Promsie 中你定义了 throw , 而且如果 throw 在最后(resolve之后)定义,就算有错误/异常,一旦状态变为resolve,就不会被抛出(throw不执行)。
步骤
- 首先new一个对象(例子中new了一个匿名的Promise对象,直接new匿名对象然后链式操作是那些骚东西做的事,新手入门的不要学啊,不然很容易晕)
- resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
- reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
- 对resolve或者reject进行处理
上代码
//正常版(ES6)
new Promise((resolve, reject)=>{
// 一段耗时的异步操作
resolve('嘿嘿嘿成功') // 数据处理完成
reject('嘿嘿嘿失败') // 数据处理出错
}
).then(
(res) => {console.log(res)}, // 成功
(err) => {console.log(err)} // 失败
)
/*
*ES5版 本质与上面的无差
*但是上方new了一个匿名对象
*后面只能进行链式操作
*不能用对象名`.`then这样的形式调用
*刚入门容易晕
*/
var promise = new Promise(function(resolve,reject){
resolve("嘿嘿嘿成功")
reject("嘿嘿嘿失败")
});
promise.then(function(res){
console.log(res)
},function(err){
console.log(err)
})
跑一下:
下面将resolve注掉
没有了成功状态,只能失败了
其中对于两种状态的处理可以是任意回调函数,可以有效的解决回调地狱,提高代码可读性。
.catch()
人有祸福,世事无常。如果promise里面的任务既没有resolve,也没有reject,怎么办?
上面提到了常用的api中还有catch,这个方法是用来捕捉错误的。
你大概可以理解为:
catch == then(undefined,function(err){ })
catch == then(undefined,(err)=>{ })
let pro = new Promise((resolve, reject) => {
throw "error";
});
pro.catch((err)=> {
console.log("catch " + err);// catch error
});
Promise对象内部其实自带了try catch,当同步代码发生运行时错误时,会自动将错误对象作为值reject,这样就会触发catch注册的回调。
现在到这里为止,你能掌握上述就说明已经学会了promise,但是想玩得6还是不太够的,因为对于then链(你可以理解为一直then下去)的保姆级教程由于篇幅,本文没有提到,但是开发中很常用(包括async/await),有还想深入的同学推荐去阮一峰ES6教程。