Promise定义
Promise是CommonJs的规范之一,包含resolve,reject,done,fail,then等方法,能够帮助我们控制代码的流程,避免函数的多层嵌套。异步在web开发中越来越重要,对于开发人员来说,J非线性执行的编程会让开发者觉得难以掌控,而Promise可以让我们更好地掌控代码的执行流程,jQuery等流行的js库都已经实现了这个对象,现在ES6已经原生实现了Promise。
场景说明:
有时候会遇到这样的情况,需要发两个异步请求,而第二个请求需要用到第一个返回结果的数据:
ajax({ url: url1, success: function(data) { ajax({ url: url2, data: data, success: function() { } }); } });
稍微整理一下,把后一个调用封装成一个函数,就是酱紫滴:
function A() { ajax({ url: url1, success: function(data) { B(data); } }); } function B(data) { ajax({ url: url2, success: function(data) { ...... } }); }
如果异步请求C又需要用到B的结果,又需要一层。如果需要很多层,代码可读性会降低,最后不忍直视了就。所以就有了Promise。有了Promise,代码就是酱紫了:
new Promise(A).done(B);
很清爽很DRY有木有?
ES6已经实现了Promise,不过也可以自己写一个Promise对象:
用两个数组(doneList和failList)来存储成功时的回调函数队列和失败时的回调函数队列。
此对象的方法和属性:
1.state: 当前执行状态,有pending、resolved、rejected3种取值
2.done: 向doneList中添加一个成功回调函数
3.then: 分别向doneList和failList中添加回调函数
4.always: 添加一个无论成功还是失败都会调用的回调函数
5.resolve: 将状态更改为resolved,并触发绑定的所有成功的回调函数
6.reject: 将状态更改为rejected,并触发绑定的所有失败的回调函数
7.when: 参数是多个异步或者延迟函数,返回值是一个Promise兑现,当所有函数都执行成功的时候执行该对象的resolve方法,反之执行该对象的reject方法
具体实现:
var Promise = function() { this.doneList = []; this.failList = []; this.state = ‘pending‘; }; Promise.prototype = { constructor: ‘Promise‘, resolve: function() { this.state = ‘resolved‘; var list = this.doneList; for(var i = 0, len = list.length; i < len; i++) { list[0].call(this); list.shift(); } }, reject: function() { this.state = ‘rejected‘; var list = this.failList; for(var i = 0, len = list.length; i < len; i++){ list[0].call(this); list.shift(); } }, done: function(func) { if(typeof func === ‘function‘) { this.doneList.push(func); } return this; }, fail: function(func) { if(typeof func === ‘function‘) { this.failList.push(func); } return this; }, then: function(doneFn, failFn) { this.done(doneFn).fail(failFn); return this; }, always: function(fn) { this.done(fn).fail(fn); return this; } };
这个不支持链式调用,可以再来个支持链式调用的:
var MPromise = function(func){ this.doneList = []; this.state = ‘pending‘; func(this.resolve.bind(this)); this.self = this; } MPromise.prototype = { resolve: function(){ var args = arguments[0]; while(true){ args = [args]; this.lastargs = args; if( this.doneList.length == 0 ){ this.state = ‘done‘; break; } args = this.doneList.shift().apply(this, args); if( args instanceof MPromise ){ this.self = args; args.doneList = args.doneList.concat(this.doneList.slice(0)); this.state = ‘done‘; this.doneList.length = 0; break; } } }, then: function(callback){ this.doneList.push(callback); if( this.state == ‘done‘ ){ this.state = ‘pending‘; this.resolve.apply(this, this.lastargs); } return this.self; } }
ES6-Promise
ES6提供了原生Promise对象:从语法上说,Promise是一个对象,从中可以获取异步操作的消息。
基本用法:
ES6中的Promise对象是一个构造函数,用来生成Promise实例。
var promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } });
Promise对象接收一个函数作为参数,这个函数的两个参数分别是resolve和reject,这两个函数由Javascript引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
promise.then(function(value) { // success }, function(error) { // failure });
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Reject时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。