您的位置:首页 > 其它

ES6 -- Promise对象

2017-08-02 09:16 239 查看
Promise是一种异步编程的解决方案,ES6提供原声的Promise,它比传统的解决方案,回调函数和事件,更加合理和强大。

Promise对象有以下两个特点:

1、对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending, resulved, rejected。只有异步操作的结果,可以决定是哪一种状态。

2、状态一旦改变,就不会再变化,并且任何时候都可以得到这个结果。

实用Promise对象,可以将异步操作用同步操作的流程表达出来,避免了层层嵌套的回调函数。

基本用法

var promise = new Promise(function(resolve, reject) {
// ... some code

if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});


注意,函数resolve, reject由JS引擎提供,不用自己部署。

resolve函数的作用是将Promise对象的状态从“未完成”变为“成功”(即从 Pending 变为 Resolved),在异步调用成功的时候使用,并将异步操作的结果作为参数传递出去;reject函数将Promise对象的状态从“未完成”变为“失败”(即从 Pending 变为 Rejected),在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去。

promise.then(function(value) {
// success
}, function(error) {
// failure
});


Promise实例生成以后,可以用then方法分别指定Resolved状态和Rejected状态的回调函数。

一个完整的例子:

function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
}

timeout(100).then((value) => {
console.log(value);
});


timeout方法返回一个Promise实例。当Promise实例的状态变为Resolved,就会触发then方法绑定的回调函数。

另外,Promise对象在新建后就会立即执行。

下面是用Promise对象实现Ajax的例子:

var getJSON = function(url) {
var promise = new Promise(function(resolve, reject){
var client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();

function handler() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
});

return promise;
};

getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});


Promise“嵌套”

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。

reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例:

var p1 = new Promise(function (resolve, reject) {
// ...
});

var p2 = new Promise(function (resolve, reject) {
// ...
resolve(p1);
})


上面代码中,p1和p2都是 Promise 的实例,

但是,重要的来了,p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。

这时,p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是Pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是Resolved或者Rejected,那么p2的回调函数将会立刻执行。

注意,调用resolve或reject并不会终结 Promise 的参数函数的执行。

new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1


Promise.prototype.then()

then方法的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。

then方法可以链式调用。

getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function funcA(comments) {
console.log("Resolved: ", comments);
}, function funcB(err){
console.log("Rejected: ", err);
});


上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为Resolved,就调用funcA,如果状态变为Rejected,就调用funcB。

Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。

Promise.resolve()

Promise.resolve()可以将现有对象转化为Promise对象。

等价于:

Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))


Promise.resolve方法的参数分成四种情况。

1、参数是一个Promise实例

如果参数是Promise实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

2、参数是一个thenable对象

thenable对象指的是具有then方法的对象,比如下面这个对象。

let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};


Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法。

3、参数不是具有then方法的对象,或根本就不是对象

如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为Resolved。

var p = Promise.resolve('Hello');

p.then(function (s){
console.log(s)
});
// Hello


4、不带有任何参数

Promise.resolve方法允许调用时不带参数,直接返回一个Resolved状态的Promise对象。

所以,如果希望得到一个Promise对象,比较方便的方法就是直接调用Promise.resolve方法。

需要注意的是,立即resolve的Promise对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

Promise.reject()

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Promise