前端初学者经常会问,我如何在ajax1结束之后才启动ajax2呢?我怎么做才能在所有的ajax结束之后触发某程序呢?亦或是哎真是烦,5个ajax套在一起,原来的逻辑是什么呀!
一个稍微有点经验的前端程序员可能会直接丢给你这样一个答案——Promise。
首先要明确一点,promise是一个规范,它并是什么新技术,在我看来它就是一种编程方式。核心就是解决地狱回掉带来的问题,优化异步流程控制。置于什么是地狱回掉自行百度哈。。。。。。
下面开始我们今天的重点戏码😀
既然promise是一个规范,那么我们用js去按照规范写就好了,由于js一切皆对象的原因(其实我们在使用基础数据类型的时候用的也是对象哦,它的名字叫包装类)我们就用一个Mypromise对象来代表,接下来我们用构造+原型的方式(js常用构建类的方式)创建这个类。
//初始化状态值 var PENDING = 1, FULFILLED = 2, REJECJT = 3, BREACK = 4; function MyPromise(fn) { if(typeof fn !== 'function') throw new TypeError("传入参数非函数") var mypromise = this; mypromise.value = null, mypromise.status = PENDING, mypromise.resolve = null, mypromise.reject = null; //想象成ajax中的sucess方法 function resolve(data) { mypromise.over(FULFILLED, data); } //想象成ajax中的err方法 function reject(err) { mypromise.over(REJECJT, err); }
//把回掉注册到ajax中的suc与err之中 fn(resolve, reject) } MyPromise.prototype.then = function(resolve, reject) { } MyPromise.prototype.over = function(status, value) { }
解读一下以上代码:(es6还没普及😭,const不能用)根据规范呢,我先定义了4个常量(规范里不是三个吗,你怎么是4个呀,山人自有妙计😀)。然后呢按照异步方法的通用特点,存在失败和成功的回掉,去初始化这个类,并在原型中定义了核心then方法以及ajax回掉之后都会触发的over方法(为什么要有over方法呢——减少重复)。
接下来看看over的具体实现:
MyPromise.prototype.over = function(status, value) { var mypromise = this, callback = null; if(mypromise.status === BREACK) return; mypromise.status = status, mypromise.value = value; setTimeout(function() { callback = (status === FULFILLED ? mypromise.resolve : mypromise.reject); callback && callback(value) }) }
请先忽略我红色部分的代码🙂,over中会根据ajax回掉的类型(失败,成功)来触发对应的注册在该promise上的resolve与reject且只有当callback存在才能执行。置于为什么要将回掉放到settimeout中去呢,为了使后面的then方法先执行。
重头戏then:
MyPromise.prototype.then = function(resolve, reject) { var mypromise = this; return new MyPromise(function(onResolv, onReject) { function trigerResolv(value) { var nextPromise = typeof resolve === 'function' && resolve(value) || value if(nextPromise instanceof MyPromise) { nextPromise.then(function(value) { onResolv(value); }, function(value) { onReject(value); }) } else { //判断在成功之后是否需要终止回掉 if(nextPromise === BREACK) { mypromise.status = BREACK; return; } onResolv(nextPromise); } } function trigerReject(value) { var nextPromise = typeof reject === 'function' && reject(value) || value onReject(nextPromise) } if(mypromise.status === PENDING) { mypromise.resolve = trigerResolv; mypromise.reject = trigerReject; } if(mypromise.status === FULFILLED) { trigerResolv(mypromise.value) } if(mypromise.status === REJECJT) { trigerReject(mypromise.value) } }) }
每一个then新建并返回promiseB对象(实现链式调用),对then方法中resolve进行封装,生成方法a赋值给上一个promiseA的回掉方法中。promiseA回掉方法触发之后触发a。如果返回值为promiseC对象,那么将promiseB的回掉放到promiseC的回掉之中,否则在promiseC中传入promiseA的value.
现在来仔细看看红色部分的代码,是不是有所领悟呢?当ajax成功的时候也需要终止整个流程时就需要这第四中状态了,使用方法就是在then中的resolve中return
BREACK就ok了,当在then方法中返回BREACK的就之后,那么上文中的promiseB的回掉不会执行,也就无法触发promiseB中注册的then方法了。
参考:http://www.ituring.com.cn/article/66566
http://www.cnblogs.com/huansky/p/6064402.html