promise异步编程
一.起源
JavaScript中的异步由来已久,不论是定时函数,事件处理函数还是ajax异步加载都是异步编程的一种形式,我们现在以nodejs中实现三个小球的运动为例:
这里嵌套了6个异步回调函数,他们的执行时刻都是不可预测的并且这样写代码也不符合普通程序的执行流程,所以,问题来了。promise提供了一个解决上述问题的模式。
animate(ball1,100,function () {
animate(ball2,200,function () {
animate(ball3,300,function () {
animate(ball3,150,function () {
animate(ball2,150,function () {
animate(ball1,150,function () {
})
})
})
})
})
})
2.接口
promise唯一接口then方法,它需要2个参数,分别是resolveHandler和rejectedHandler。并且返回一个promise对象来支持链式调用。
promise的构造函数接受一个函数参数,参数形式是固定的异步任务。
三.实现
要实现promise对象,首先要考虑几个问题:
1.promise构造函数中要实现异步对象状态和回调函数的剥离,并且分离之后能够还能使回调函数正常执行
2.如何实现链式调用并且管理状态
首先是构造函数:
/*引入promise对象*/
var Promise=window.Promise
function promiseAnimate(ball,distance) {
return new Promise(function (resolve, reject) {
function _animate() {
setTimeout(function () {
var marginLeft = parseInt(ball.style.marginLeft, 10)
if (marginLeft === distance) {
resolve()
} else {
if (marginLeft < distance) {
marginLeft++
} else {
marginLeft--
}
ball.style.marginLeft = marginLeft+'px'
_animate()
}
}, 13)
}
_animate();
})
}
构造函数接受一个异步函数,并且执行这个异步函数,修改promise对象的状态和结果。
回调函数方法then:
/*用romise的方式实现小球的运动*/
promiseAnimate(ball1,100)
.then(function () {
return promiseAnimate(ball2,200)
})
.then(function () {
return promiseAnimate(ball3,300)
})
.then(function () {
return promiseAnimate(ball3,150)
})
.then(function () {
return promiseAnimate(ball2,150)
})
.then(function () {
return promiseAnimate(ball1,150)
})
四、Promise实现小球的运动的完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise animation</title>
<style>
.ball{
width: 40px;
height: 40px;
border-radius: 20px;
}
.ball1{
background: red;
}
.ball2{
background: yellow;
}
.ball3{
background: green;
}
</style>
<script src="./node_modules/bluebird/js/browser/bluebird.js"></script>
</head>
<body>
<div class="ball ball1" style="margin-left: 0;"></div>
<div class="ball ball2" style="margin-left: 0;"></div>
<div class="ball ball3" style="margin-left: 0;"></div>
<script>
var ball1=document.querySelector('.ball1')
var ball2=document.querySelector('.ball2')
var ball3=document.querySelector('.ball3')
function animate(ball,distance,cb) {
setTimeout(function () {
var marginLeft=parseInt(ball.style.marginLeft,10)
if(marginLeft===distance){
cb && cb()
}else{
if(marginLeft<distance){
marginLeft++
}else {
marginLeft--
}
ball.style.marginLeft=marginLeft+'px'
animate(ball,distance,cb)
}
},13)
}
/*引入promise对象*/
var Promise=window.Promise
function promiseAnimate(ball,distance) {
return new Promise(function (resolve, reject) {
function _animate() {
setTimeout(function () {
var marginLeft = parseInt(ball.style.marginLeft, 10)
if (marginLeft === distance) {
resolve()
} else {
if (marginLeft < distance) {
marginLeft++
} else {
marginLeft--
}
ball.style.marginLeft = marginLeft+'px'
_animate()
}
}, 13)
}
_animate();
})
}
/*用romise的方式实现小球的运动*/
promiseAnimate(ball1,100)
.then(function () {
return promiseAnimate(ball2,200)
})
.then(function () {
return promiseAnimate(ball3,300)
})
.then(function () {
return promiseAnimate(ball3,150)
})
.then(function () {
return promiseAnimate(ball2,150)
})
.then(function () {
return promiseAnimate(ball1,150)
})
</script>
</body>
</html>