Promise

Promise对象用于一个异步操作的成功(或失败)及其结果值的表示。(简单点说,就是我们处理异步请求,经常会进行一些承诺,如果我赢了你嫁给我,我输了我嫁给你,这类的诺言,这就是Promise的中文意思,一个诺言,一个成功,一个失败)

ES6将其写进了语言标准,统一了用法,并且原生提供了Promise对象。

我们可以先看一下Promise到底是什么?chrome上输入console.dir(Promise),就出来了。

我们可以看到,原来Promise是个构造函数,它有all,race,reject,resolve方法,在其原型prototype上有catch,then方法。

有的初级的小伙伴就问了,呀呀呀,这个Promise怎么还有方法呢?Promise也是函数哦,函数是对象,当然可以有方法啦,0--^^--0。毫无疑问,原型prototype上的方法就是供Promise的实例对象使用的。

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。resolve函数的作用是,将Promise对象的状态从“”未完成”变为“成功”,在异步操作成功时调用,并将异步操作的结果作为参数传递出去;reject函数的作用是,将Promise对象的状态从“”未完成”变为“失败”,在异步操作失败时调用,并将异步操作的错误作为参数传递出去;

既然这样,我们先实例化一个Promise。

var promise = new Promise(function(resolve, reject) {
    setTimeout(resolve('some thing happed'), 200)
})
promise.then(function(data){
     console.log('success:', data) 
}, function(err){
     console.log('error:', err)
})

首先得说明,Promise.prototype.then,可以接受两个回调函数,当成功resolve时调用第一个回调,失败时调用第二个回调,第二个回调可以省略。

所以上面的结果为 success: some thing happed 

 

初步了解Promise后,我们用Promise对象实现一个AJAX操作的例子。

var getJSON = function(url) {
    var promise = new Promise(resolve, reject) {
        var client = new XMLHttpRequest();
        client.open('GET', url);
        client.onreadystatechange = function(){
            if (this.readyState !== 4) {
                return
            }
            if (this.status === 200) {
                resolve(this.response)
            } else {
                reject(new Error(this.statusText))
            }
        }    
    }
    return promise
}

getJSON('/db.json').then(function(json){
    console.log('Result:',  json)    
}, function(error){
    console.log('error:', error)
})

上面的代码中,getJSON是对XMLHttpRequest对象的Promise封装,用于发出一个针对JSON数据的HTTP请求,并返回一个Promise对象。需要注意的是,在getJSON内部,resolve函数和reject函数调用时都带有参数。reject函数的参数通常是Error对象的实例,而resolve函数的参数除了正常的值外,还可以是另一个Promise对象。

举例说明

var p1 = new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('fail')), 3000)
})
var p2 = new Promise(function (resolve, reject) {
    setTimeout(() => resolve(p1), 1000)
})
p2.then(result => console.log('success:', result))
p2.catch(error => console.log('error:', error))

在这种情况下,p1的状态会传递给p2,p1的状态决定了p2的状态,一秒钟后,p1的状态还是pending,所以p2也是pending,三秒后,p1的状态变为failed,p2的状态也变为failed,所以调用catch方法,返回结果为error: Error: fail,利用这个特性,我们可以用来控制多个异步操作的流程???

需要注意的是Promise.prototype.then方法和Promise.prototype.catch方法返回的都是Promise对象,所以可以继续调用then方法。

 

前面有看到,Promise构造函数有all和race方法,让我们逐一击破

Promise.all方法用于将多个Promise实例包装成一个新的Promise实例

var p = Promise.all([p1, p2, p3])

此时p的状态有p1,p2,p3的状态决定,规则有两条,

1、只有p1,p2,p3的状态都变成Fullfilled时,p的状态才会变成Fullfilled,此时p1,p2,p3的返回值组成一个数组,传递给p的回调函数

2、只要p1,p2,p3中一个被Rejected,p的状态就变成Rejected,此时第一个被Rejected的实例的返回值传递给p的回调函数

这就是all的意义啦。比如

var promises = [2,3,4].map(function(id){
    return getJSON('/post/' + id + '.json'); 
})
Promsie.all(promises).then(function(posts){
    //3个各自成功返回值组成的数组
}).catch(function(reason){
    //第一个失败返回值
})

Promise.race()同样是将多个Promise实例包装成一个新的Promise实例

var p = Promise.race([p1,p2,p3])

只要p1,p2,p3中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数。就不在赘述。

 

前面也有看到,Promise构造函数还有resolve和reject方法,它们各自又有什么用呢?

有时,我们需要将现有对象转化为Promise对象,Promise.resolve方法就起到这个作用。如 

var jsPromise = Promise.resolve($.ajax('/whatever.json'));
jsPromise.then(function(data){
    //成功
    console.log('success:', data)
},function(err){
    //失败
    console.log('error:', err)
})

上面的代码可以将jquery生成的deferred对象转化新的Promise对象,jsPromise调用哪个方法还是取决于jquery中deferred对象的状态。

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

如果Promise.resolve方法的参数不是具有then()方法的对象,则返回一个新的Promise对象,且其状态为Resolved。

var p = Promise.resolve('Hello')
p.then(function(s){
    console.log(s)
})
//hello

由于字符串'hello'不属于异步操作(没有then方法),返回Promise实例的状态从一生成就是Resolved,所以回调函数会立即执行。

 

Promise.reject(reason)则是返回一个新的Promise实例,状态为Rejected。Promise.reject方法的参数reason会被传递给实例的回调函数

var p = Promise.reject('出错了')
//等同于
var p = new Promise((resolve,reject) => reject('foo'))
p.then(null, function (s) {
   console.log(s)
})
//出错了

 

posted @ 2017-07-18 23:42  wbxjiayou  阅读(333)  评论(0编辑  收藏  举报