Promise 的含义
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
特点
- 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
缺点
Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
实例分析
/* 用于描述思维的代码 */
function Promise(executor) {
// 共有三种状态:pending(准备)、fulfilled(完成)、rejected(拒绝)
this.PromiseStatus = 'pending';
// 用于存储返回的数据
this.PromiseValue;
// 完成
var resolve = function(reson) {};
// 拒绝
var reject = function(reson) {};
...
// 开始执行承诺
executor(resolve, reject);
}
Promise.prototype.then = function() {};
Promise.prototype.chain = function() {};
Promise.prototype.catch = function() {};
例:
var http = {
get: function(url) {
var promise = new Promise(function(resolve, reject) {
$.ajax({
url: url,
method: 'get',
success: function(data) {
resolve(data);
},
error: function(xhr, statusText) {
reject(statusText);
}
});
});
return promise;
}
};
http.get('solve.php').then(function(data) {
return data;
}, function(err) {
return Promise.reject('Sorry, file not Found.');
}).then(function(data) {
document.write(data);
}, function(err) {
document.write(err);
});
分析过程:
当http调用get()方法时候执行executor(也就是例子里的Promise里的参数函数)。注:实例化Promise的时候就会执行参数里的函数
执行executor内容发出了ajax请求,成功返回,且有返回结果的时候,执行resolve(data),resolve把promise的PromiseStatus的值设为fulfilled, PromiseValue的值设为data;同样reject也是类似,只是把PromiseStatus的值设为rejected
当PromiseStatus的值被改来不为pending的时候就会出发promise的then函数 ,then方法的参数接受两个方法参数,分别对应fulfilled和rejected的回调,触发条件是Promise.PromiseStatus的值。 注:这里的then也是个异步
当调用Promise的then方法的时候,例如 promise.then( fun1(data){ … return result }, fun2(data){… return result}) 返回的依旧是一个Promise对象,此时新的Promise对象的PromiseStatus的值就是fun1/fun2函数里返回的值 。所以依旧可以再调用then方法,形成链式调用
Promise原型上三个重要的方法
Promise.prototype.then 、Promise.prototype.catch 、Promise.prototype.finnally
Promise.prototype.catch方法是.then(null,rejection)的别名,用于制定发生错误时候的回调函数
Promise.prototype.finnally则是无论状态如何都会调用的方法
Promise.all()
const p = Promise.all([p1, p2, p3]);
// Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例,
//p的状态:fulfilled: 当p1、p2、p3的状态全为fulfilled,所有返回值组成一个数组作为p的值
//rejected: 当p1、p2、p3其中一个为rejected,首先状态为rejected的值将会传给p
Promise.race()
const p = Promise.race([p1, p2, p3]);
Promise.race()也是将多个Promise实例,包装成一个新的Promise实例
p的状态,fulfilled: 当p1、p2、p3的状态有一个为fulfilled,首先状态为fulfilled的值将会传给p
rejected: p1、p2、p3的状态全为rejected,所有返回值组成一个数组作为p的值
Promise.resolve()、Promise.reject()
//Promise.resolve(): 返回Promise对象,
//参数: 1、Promise对象,直接返回该Promise对象。
// 2、参数是一个thenable对象(),将会将该对象变成Promise对象,并立即执行thenable对 象的then()。
// 3、不是Promise和thenable对象,或者不是对象,直接放回一个状态为fulfilled的Promise 对象,且将参数作为值传入。
// 4、不带参数,直接放回一个状态为fulfilled的Promise对象。
//Promise.reject(): 返回状态为rejected的Promise对象,
// 参数: 直接作为返回Promise对象的值
Promise.try
问题引入:
下面的代码存在一个问题,因为then是异步的,所以要到本轮事件循环的末尾执行,如果Promise里包裹的是异步请求,这个没毛病,但如果不是(有些时候我们都不知道是不是异步请求),同步就被异步执行了
const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');
// next
// now
解决方法1,利用async
const f = () => console.log('now');
(async () => f())();
console.log('next');
// now
// next
解决方法2,用立即执行的匿名函数
const f = () => console.log('now');
(
() => new Promise(
resolve => resolve(f())
)
)();
console.log('next');
// now
// next
2、当抛出一些同步错误,比如(数据库连接错误)就只能用try,catch处理了,如下
try {
database.users.get({id: userId}) //dtabase.user.get()返回一个Promise对象
.then(...)
.catch(...)
} catch (e) {
// ...
}
上面个两种情况发生时候,我们都可以用Promise.try(),很优雅的解决问题
Promise.try(database.users.get({id: userId}))
.then(...)
.catch(...)