Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最先提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise
对象。git
所谓Promise
,简单说就是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果。从语法上说,Promise 是一个对象,从它能够获取异步操做的消息。Promise 提供统一的 API,各类异步操做均可以用一样的方法进行处理。github
Promise
对象有如下两个特色。编程
(1)对象的状态不受外界影响。Promise
对象表明一个异步操做,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操做的结果,能够决定当前是哪种状态,任何其余操做都没法改变这个状态。这也是Promise
这个名字的由来,它的英语意思就是“承诺”,表示其余手段没法改变。数组
(2)一旦状态改变,就不会再变,任什么时候候均可以获得这个结果。Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种状况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。若是改变已经发生了,你再对Promise
对象添加回调函数,也会当即获得这个结果。这与事件(Event)彻底不一样,事件的特色是,若是你错过了它,再去监听,是得不到结果的。promise
有了Promise
对象,就能够将异步操做以同步操做的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操做更加容易。bash
Promise
也有一些缺点。首先,没法取消Promise
,一旦新建它就会当即执行,没法中途取消。其次,若是不设置回调函数,Promise
内部抛出的错误,不会反应到外部。第三,当处于pending
状态时,没法得知目前进展到哪个阶段(刚刚开始仍是即将完成)。框架
Promise
构造函数接受一个函数做为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由 JavaScript 引擎提供,不用本身部署。异步
resolve
函数的做用是,将Promise
对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操做成功时调用,并将异步操做的结果,做为参数传递出去;reject
函数的做用是,将Promise
对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操做失败时调用,并将异步操做报出的错误,做为参数传递出去。异步编程
var p=new Promise(function(resolve,rejcet){
setTimeout(function(){
if(true){
//异步操做成功
resolve('success');
}else{
//异步操做失败
rejcet('failure');
}
},1000);
});
p.then(function(value){
//成功的回调
console.log(value);
},function(error){
//失败的回调
console.log(error);
});复制代码
从demo中能够看到,在ES6中Promise
对象是一个构造函数,用来生成Promise
实例。而且Promise
实例生成之后,能够用then
方法分别指定resolved
状态和rejected
状态的回调函数。函数
function Promise(callback) {
var self = this //promise实例
self.status = 'PENDING' // Promise当前的状态
self.data = undefined // Promise的值
self.onResolvedCallback = [] // Promise resolve时的回调函数集
self.onRejectedCallback = [] // Promise reject时的回调函数集
callback(resolve, reject) // 执行executor并传入相应的参数
function resolve(value){
}
function reject(error){
}
}
// 添加咱们的then方法
Promise.prototype.then=function(){
}复制代码
咱们先建立一个Promise构造函数,并传入一个回调函数callback,callback里面传入两个函数做为参数,一个是resove,一个是reject。并在Promise的原型上加入咱们的then方法。框架搭好了,接下来咱们来一点点的完善框架里面的内容,能够这么说,把resolve,reject和then补充完,基本能够说就是把Promise完成了。
function Promise(callback) {
var self = this
self.status = 'PENDING' // Promise当前的状态
self.data = undefined // Promise的值
self.onResolvedCallback = [] // Promise resolve时的回调函数集
self.onRejectedCallback = [] // Promise reject时的回调函数集
callback(resolve, reject) // 执行executor并传入相应的参数
function resolve(value){
if(self.status=='PENDING'){
self.status=='FULFILLED';
self.data=value;
// 依次执行成功以后的函数栈
for(var i = 0; i < self.onResolvedCallback.length; i++) {
self.onResolvedCallback[i](value)
}
}
}
function rejecte(error){
if (self.status === 'PENDING') {
self.status = 'REJECTED'
self.data = error;
// 依次执行失败以后的函数栈
for(var i = 0; i < self.onRejectedCallback.length; i++) {
self.onRejectedCallback[i](error)
}
}
}
}复制代码
then方法是Promise的核心,所以这里会花比较大的篇幅去介绍then:
一个promise的then接受两个参数:
promise.then(onFulfilled, onRejected)复制代码
onFulfilled
和 onRejected
都是可选参数。
onFulfilled
不是函数,其必须被忽略onRejected
不是函数,其必须被忽略onFulfilled 特性
若是 onFulfilled
是函数:
promise
执行结束后其必须被调用,其第一个参数为 promise
的终值,也就是resolve传过来的值promise
执行结束前其不可被调用onRejected 特性
若是 onRejected
是函数:
promise
被拒绝执行后其必须被调用,其第一个参数为 promise
的据因,也就是reject传过来的值promise
被拒绝执行前其不可被调用调用时机
onFulfilled
和 onRejected
只有在执行环境堆栈仅包含平台代码时才可被调用(平台代码指引擎、环境以及 promise 的实施代码)
调用要求
onFulfilled
和 onRejected
必须被做为函数调用(即没有 this
值,在严格模式(strict) 中,函数 this
的值为 undefined
;在非严格模式中其为全局对象。)
屡次调用
then
方法能够被同一个 promise
调用屡次
promise
成功执行时,全部 onFulfilled
需按照其注册顺序依次回调promise
被拒绝执行时,全部的 onRejected
需按照其注册顺序依次回调then
方法必须返回一个 promise
对象
promise2 = promise1.then(onFulfilled, onRejected);复制代码
onFulfilled
或者 onRejected
返回一个值 x
,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)
onFulfilled
或者 onRejected
抛出一个异常 e
,则 promise2
必须拒绝执行,并返回拒因 e
onFulfilled
不是函数且 promise1
成功执行, promise2
必须成功执行并返回相同的值onRejected
不是函数且 promise1
拒绝执行, promise2
必须拒绝执行并返回相同的据因不论 promise1
被 reject 仍是被 resolve 时 promise2
都会被 resolve,只有出现异常时才会被 rejected。
每一个Promise对象均可以在其上屡次调用then方法,而每次调用then返回的Promise的状态取决于那一次调用then时传入参数的返回值,因此then不能返回this,由于then每次返回的Promise的结果都有可能不一样。
Promise.prototype.then = function(onResolved, onRejected) {
var self = this
var promise2
// 根据标准,若是then的参数不是function,则咱们须要忽略它,此处以以下方式处理
onResolved = typeof onResolved === 'function' ? onResolved : function(value) {}
onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {}
if (self.status === 'resolved') {
// 若是promise1(此处即为this/self)的状态已经肯定而且是resolved,咱们调用onResolved
// 由于考虑到有可能throw,因此咱们将其包在try/catch块里
return promise2 = new Promise(function(resolve, reject) {
try {
var x = onResolved(self.data)
if (x instanceof Promise) { // 若是onResolved的返回值是一个Promise对象,直接取它的结果作为promise2的结果
x.then(resolve, reject)
}
resolve(x) // 不然,以它的返回值作为promise2的结果
} catch (e) {
reject(e) // 若是出错,以捕获到的错误作为promise2的结果
}
})
}
// 此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就再也不作过多解释
if (self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
try {
var x = onRejected(self.data)
if (x instanceof Promise) {
x.then(resolve, reject)
}
} catch (e) {
reject(e)
}
})
}
if (self.status === 'pending') {
// 若是当前的Promise还处于pending状态,咱们并不能肯定调用onResolved仍是onRejected,
// 只能等到Promise的状态肯定后,才能确实如何处理。
// 因此咱们须要把咱们的**两种状况**的处理逻辑作为callback放入promise1(此处即this/self)的回调数组里
// 逻辑自己跟第一个if块内的几乎一致,此处不作过多解释
return promise2 = new Promise(function(resolve, reject) {
self.onResolvedCallback.push(function(value) {
try {
var x = onResolved(self.data)
if (x instanceof Promise) {
x.then(resolve, reject)
}
} catch (e) {
reject(e)
}
})
self.onRejectedCallback.push(function(reason) {
try {
var x = onRejected(self.data)
if (x instanceof Promise) {
x.then(resolve, reject)
}
} catch (e) {
reject(e)
}
})
})
}
}
// 为了下文方便,咱们顺便实现一个catch方法
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}复制代码
最后附上完整的代码:
Promise.prototype.then = function(onResolved, onRejected) {
var self = this
var promise2
// 根据标准,若是then的参数不是function,则咱们须要忽略它,此处以以下方式处理
onResolved = typeof onResolved === 'function' ? onResolved : function(value) {}
onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {}
if (self.status === 'resolved') {
// 若是promise1(此处即为this/self)的状态已经肯定而且是resolved,咱们调用onResolved
// 由于考虑到有可能throw,因此咱们将其包在try/catch块里
return promise2 = new Promise(function(resolve, reject) {
try {
var x = onResolved(self.data)
if (x instanceof Promise) { // 若是onResolved的返回值是一个Promise对象,直接取它的结果作为promise2的结果
x.then(resolve, reject)
}
resolve(x) // 不然,以它的返回值作为promise2的结果
} catch (e) {
reject(e) // 若是出错,以捕获到的错误作为promise2的结果
}
})
}
// 此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就再也不作过多解释
if (self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
try {
var x = onRejected(self.data)
if (x instanceof Promise) {
x.then(resolve, reject)
}
} catch (e) {
reject(e)
}
})
}
if (self.status === 'pending') {
// 若是当前的Promise还处于pending状态,咱们并不能肯定调用onResolved仍是onRejected,
// 只能等到Promise的状态肯定后,才能确实如何处理。
// 因此咱们须要把咱们的**两种状况**的处理逻辑作为callback放入promise1(此处即this/self)的回调数组里
// 逻辑自己跟第一个if块内的几乎一致,此处不作过多解释
return promise2 = new Promise(function(resolve, reject) {
self.onResolvedCallback.push(function(value) {
try {
var x = onResolved(self.data)
if (x instanceof Promise) {
x.then(resolve, reject)
}
} catch (e) {
reject(e)
}
})
self.onRejectedCallback.push(function(reason) {
try {
var x = onRejected(self.data)
if (x instanceof Promise) {
x.then(resolve, reject)
}
} catch (e) {
reject(e)
}
})
})
}
}
// 为了下文方便,咱们顺便实现一个catch方法
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}复制代码