1

Promise对象是一种异步编程的解决方案,比传统的解决方案——会掉函数和事件——更合理和强大。
Promise有三种状态:pending(进行中)、Resolved(Fulfilled,已完成)和Rejected(已失败);而且状态一旦改变,就不会再发生改变,Promise对象的状态只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生了,状态就凝固了,不会再变了。Promise有一些缺点,就是无法取消,一旦新建它就会执行,无法中途取消;其次如果不设置回调函数,Promise内部抛出的错误,不会反应到外部;第三Pending状态时,无法得知目前进展到哪一个阶段。

基本用法

Promise构造函数接受一个函数作为参数,该函数参数分别是resolve和reject方法。如果成功,则用resolve将Promise的状态改为成功,即从Pending变为resolved;如果异步失败,则从Pending改为rejected。

基本用法

var promise = new Promise(function(resolve, reject){
    if(/*异步操作成功*/){
        resolve(value);
    } else{
        reject(error);
    }
});
promise.then(function(value){
    //success
}, function(value){
    //failure
});

一个简单实用的例子

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

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

如果用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.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);
})

在resolve的方法参数除了正常值以为,还可以能是另一个Promise实例。

Promise的链式操作:Promise.prototype.then

Promise.prototype.then返回的是一个新的Promise对象,因此可以写成链式的。

getJSON("/posts.json").then(function(json){
    return json.post;
}).then(function(){
    //proceed
})

上面的代码指定了两个回调函数,第一个回调函数完成以后,会将结果作为参数传入到第二个回调函数。
如果第一个回调函数返回的是Promise对象,这样后一个函数调用就将等待该Promise对象有了运行结果,才会进一步调用。

getJSON("/post/1.json").then(function(post){
    return getJSON(post.commentURL);
}).then(function(comments){
    //对comments进行处理
})

捕捉错误:Promise.prototype.catch方法

Promise.prototype.catch其实是对Promise.prototype.then(null, rejection)的调用,用于指定发生错误时的回调函数。

Promise.prototype.catch 对错误具有“冒泡”性质,会一直向后传递,直到被捕获,也就是错我总是被下一个catch语句捕获。

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 处理前两个回调函数的错误
});

Promise.all方法

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

这个方法接受一个数组作为参数,p1,p2,p3都是Promise对象的实例。p的最终状态取决于参数对象数组的状态,上例中就是p1,p2,p3来决定的。如果这三个都是fulfilled,那么p的状态就是fulfilled;如果p1,p2,p3中有一个是rejected,p的状态就是rejected.那么p的状态就是reject,会传递给p的回调函数。

// 生成一个Promise对象的数组
var promises = [2, 3, 5, 7, 11, 13].map(function(id){
  return getJSON("/post/" + id + ".json");
});

Promise.all(promises).then(function(posts) {
  // ...  
}).catch(function(reason){
  // ...
});

Promise.resolve方法,Promise.reject方法

将现有对象转我Promise对象,Promise.resolve方法就起到这个作用。

var jsPromise = Promise.resolve($.ajax('/whatever.json'));

上面jQuery生成defferred对象,转为一个新的ES6的Promise对象。
如果Promise.resolve方法的参数,不具有then方法的对象(又称thenable对象),则返回一个新的Promise对象,且他的状态为fulfilled.

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

上面生成一个新的Promise对象的实例p,它的状态为fulfilled。
Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected,Promise.reject方法的参数reason,会被传递给实例的回调函数。

async函数

async函数是用来取代回调函数的另一种方法。只要函数之前加上async的关键字,就表明该函数内部有异步操作。该异步操作返回一个Promise对象,前面用await关键字注明。当函数执行的时候,一旦遇到await就立马返回,等接触到异步操作完成,再接着执行函数体内后面的语句。

async function getStockPrice(symbol, currency) {
    let price = await getStockPrice(symbol);
    return convert(price, currency);
}

函数前面加了一个async表明该函数将返回一个Promise对象,调用该函数时,遇到await关键字,立刻返回后面的表达式产生的Promise对象,不再执行函数体后面的语句。等getStockPrice完成,在自动回到函数体内,执行剩下的语句。

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

async function asyncValue(value) {
  await timeout(50);
  return value;
}

上面代码中,asyncValue函数前面有async关键字,表明函数体内有异步操作。执行的时候,遇到await语句就会先返回,等到timeout函数执行完毕,再返回value。


jyren_Rachel
107 声望4 粉丝