分析: 从这个例子中可以看出promise的异步,因为前面的两部分代码还没有执行,就已经输出了Hi。另外可以确定的是 Resolved 一定是在 Promise之后输出的,这个顺序是不可能有问题的。
下面的例子是一个异步添加图片的url的例子
function loadImageAsync(url) { return new Promise(function(resolve, reject) { var image = new Image(); image.onload = function () { resolve(image); }; image.onerror = function() { reject(new Error('Could not load image at' + url)); } image.src = url; }); }
如果加载成功就使用resolve方法,如果失败就使用reject方法。
下面的例子是阮一峰老师封装的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); });
这里应该大家都可以看懂,值得注意的是:handler这个处理函数的使用在这里显得很巧妙。
第三部分: Promise.prototype.then()
在上一部分,我们实际上已经介绍了then()方法,而这里需要强调的有两点。
第一: then()方法是Promise原型上定义的方法。
第二:then()方法支持链式调用,上一个then()方法调用后返回的结果会传给下一个then方法中。
第一:我们再chrome中输入 Promise.prototype可以看到下面的例子:
可以看出在Promise的原型中确实是由then方法的。(注:比如我们想看Array这个内置对象有哪些方法,我们就可以直接在chrome中输入Array.prototype,然后就可以看到对应方法的列表了)
第二: then()的作用是为Promise实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。
then()由于支持链式调用,所以也可以写成下面这样:
getJSON("/posts.json").then(function(json) { return json.post; }).then(function(post) { // ... });
第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
看下面的这里例子:
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,如何这个promise的状态变成了 Resolved,那么就会执行第二个then的第一个函数, 如果变成了 Rejected,就会执行第二个第二个函数。
第四部分: Promise.prototype.catch()
Promise.prototype.catch()方法实际上是then(null, rejection)方法的别名, 这里使用catch()纯粹是为了便于使用和理解。
getJSON('/posts.json').then(function(posts) { // ... }).catch(function(error) { // 处理 getJSON 和 前一个回调函数运行时发生的错误 console.log('发生错误!', error); });
在之前的例子中,我们讲解then()方法接受两个参数,第一个参数是pending变成resolved之后执行的函数,它是必选的; 第二个参数是pending变成rejected之后执行的函数,它是可选的。
我们建议,最后不要使用第二个参数,取而代之我们最好使用catch(),如下所示:
// bad promise .then(function(data) { // success }, function(err) { // error }); // good promise .then(function(data) { //cb // success }) .catch(function(err) { // error });
值得注意的是:catch()方法返回的还是一个Promise对象,我们可以在后面继续使用then进行链式调用。
第五部分:Promise.all()
Promise.all()方法用于将多个Promise实例包装成一个新的Promise实例,如下所示:
var p = Promise.all([p1, p2, p3]);
其中的p1,p2,p3都是Promise对象实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise实例,再进一步处理。
p的状态由p1,p2,p3决定, 分成下面的两种情况:
•只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
•只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
让我们看看下面的具体的例子: