js 异步回调之Promise

先上一个大家比较熟悉的例子;
以前我们写jquery ajax请求的时候,都是这样写:

$.ajax({
    url: "test.json",
    success: function(){
      alert("hello world!");
    },
    error:function(){
      alert("error");
    }
  });

后来呢在jquery1.7版本后,我们开始这样写:

$.ajax("test.json")
  .done(function(){ alert("hello world!"); })
  .fail(function(){ alert("error"); });

很明显,更改后的代码更易懂易读了。
这个是jquery的deferred对象,jquery deferred对象就是jQuery对Promises的实现,还其他有很多实现了promises的库供开发者可用。 像微软的 WinJS.Promise, when.js, q, 和dojo.Deferred,它们暴露的都是deferred对象。Promise也已经纳入了ES6,对于jQuery实现Promises我们暂时就不讲了,今天的目的是Promise。

那Promise到底是怎么回事呢?

其实呢,Promise就是一个对象,它是用来实现异步操作的,它可以让异步代码书写起来更优雅,更便于阅读。

Promise的特性:
1、Promise对象有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败),只有异步操作结果可以改变当前状态,其他操作不能改变状态,Promise对象的状态只能从“进行中”改为“已完成”或者从“进行中”改为“失败”。

2、Promise对象的then方法,就是用来指定回调函数。一旦非同步操作完成,就调用指定的回调函数,并总是返回一个promise对象,方便链式调用。而且同一个promise的then可以调用多次。

3、then方法接受两个回调函数作为参数,第一个参数是成功Resolved时的回调,第二个是失败Reject时的回调。第二个参数是可以选的,同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。
我们现在用promise来组织一下代码。

var sleep = function (time) {
    return new Promise(function (resolve, reject) {
        console.log('test123');
        setTimeout(function () {
            resolve('test');
        }, time);
    })
};
(function(){
    console.log('start');
    sleep(3000)
    .then(function(data){
        console.log(data);
        return sleep(5000);})
    .then(function(data){
        console.log(data);
        console.log('end');
    })
})();

上面代码中,sleep方法返回一个Promise实例,表示一段时间以后才会发生的结果。输出结果:
start
test123
test
test123
test
end

好像没有什么大不了的,promises的真正强大之处在于多重的链接,在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:它有个缺点就是链过长以后,满屏幕的then,傻傻分不清业务到底干啥了,

Promise的 api

1、Promise.resolve()
2、Promise.reject()
3、Promise.prototype.then()
4、Promise.prototype.catch()
5、Promise.all() // 所有的都有完成,相当于 且
6、Promise.race() // 完成一个即可,相当于 或

1、Promise.resolve()的作用将现有对象转为Promise对象resolvedl;
Promise.resolve('test')==new Promise(resolve=>resolve('test'))
2、Promise.reject()也是返回一个Promise对象,状态为rejected;

let p=Promise.reject('error') == let p=new Promise((resolve,reject)=>reject('error'));

 p.catch(data=>{
    console.log(data);
 })

生成一个Promise对象的实例对象p,抛出错误,状态就会变为Rejected,调用p.catch()指定的回调函数。
3、.then()方法,then方法是定义在原型对象Promise.prototype上的,作用是为Promise 对象添加回调函数。

let p=new Promise(resolve=>resolve('hello'));
p.then((resolve,reject)=>{
    console.log(resolve);
}).then(function(){
  console.log('zhangsan');
})

then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。 可以使用链式操作,指定多个then(),依次执行,上面的代码输出结果:’hello‘,'zhangsan'
4、.catch():发生错误的回调函数,同样,catch方法也是定义在原型对象Promise.prototype上的,事例同Promise.reject()的例子。注:如果Promise的状态已经变为resolved,再抛出错误是无效的。

var p = new Promise(function(resolve, reject) {
  resolve('success');
  reject('fail');
});
p.then(function(value) { console.log(value) })
  .catch(function(error) { console.log(error) }); 

输出结果:success;
5、Promise.all()的作用是同时执行多个实例,同步并行,且所以的实例都返回resolve状态,Promise才会改变为resolve状态,其中一个为rejected,promise的状态就是rejected;
注:Promise.all 方法的参数可以不是数组,但是必须是一个Iterator接口对象,且返回promise实例,否则报错:error:TypeError: [object Promise] is not iterable!

let p1 =new Promise(function(resolve,reject){
        resolve(1);
});
let p2 = new Promise(function(resolve,reject){
            resolve(2);
    });
let p3 = new Promise(function(resolve,reject){
       // reject();
        resolve(3);
    });
Promise.all([p1, p2, p3]).then(function (results) {
    console.log('success:'+results);
}).catch(function(r){
    console.log("error");
    console.log(r);
});

上面代码输出:success:1,2,3;
把 p3方法改为返回 reject();输出结果是:error;
6、Promise.race()的作用也是同时执行多个实例,只要有一个实例改变状态,Promise就改为那个实例所改变的状态;

 let p1 =new Promise(function(resolve,reject){
     setTimeout(function(){
        reject(1);
     },3000)
});
let p2 = new Promise(function(resolve,reject){
    setTimeout(function(){
        resolve(2);
    },1000)
});
Promise.race([p1, p2]).then(function (results) {
    console.log('success:'+results);
}).catch(function(results){
    console.log("error:"+results);
});
输出:success: 2;

上面代码p2首先执行完毕,改变状态为resolve,所以promise的状态被改为resolve;
我们把p1的时间改为1000,p2改为3000,也就是说p1先执行完毕,promise的状态也被改变为reject,输出:error:1

如果想深入学习,可以看一下阮一峰的《ES 6标准入门》的Promise部分http://es6.ruanyifeng.com/#do...,很详细的。

你可能感兴趣的:(javascript)