es6 Promise的学习笔记

promise是什么

promise对象可以理解为一次执行的一步操作,使用promise对象之后可以用一种链式调用的方式来组织代码,使代码更加的直观!而且由于有promise.all 这样的方法存在,可以让同事执行多个操作变得简单。

为什么要使用promise?举个栗子。有一个需求,多个接口异步请求数据,然后利用这些数据来进行一系列的操作。代码如下:

$.ajax({
    url:'a.php',
    datatype:"json",
    success:function(data){
         // 获取data数据 传给下一个请求
         var id=data.id;
         $.ajax({
             url:"b.php",
             datatype:'json',
              data:{"id":id},
             success:function(){
                 
             }
         })
    }
    
})

这样的写法的原理是,当执行一些一步操作的时候,我们需要知道操作是不是完成了,所以当执行完成的时候会返回一个回调函数,然我们知道操作已经完成了,但是,这样做有几个缺点:

  1. 在需要多个操作的时候,会导致回调函数的嵌套,代码不够直观,这就是地狱回调(Callback hell)
  2. 如果前后两个参数在不需要传参的情况下,同样需要等待上一个操作完成再实行下一个操作

因此针对这种情况下,我们可以使用promise对象来解决上面的问题了~

如何创建promise

可以用new 来调用promise的构造器来进行实例化,如代码:

new promise(function(resolve,reject){
    //异步请求,
    //成功调用resolve  往下传递参数 且只接受一个参数
    //失败调用reject  往下传递参数 且只接受一个参数
    
})

对通过new 生成的promise对象为了设置其值在resolve(成功) / reject(失败) 时调用的回调函数,可以使用promise.then()实例方法。

代码如下:

promise.then(onFulfilled, onRejected)

resolve(成功)时调用onFulfilled方法,reject(失败) 时 调用onRejected方法;

Promise.then, 成功和失败时都可以使用,如果出现异常的情况下可以采用

promise.then(undefined,onRejected) 这种方式,只指定onRejected回调函数即可,不过针对这种情况下我们有更好的选择是使用catch这个方法;代码如下:

promise.catch(onRejected);

resolve 和 reject

首先看下面promise 的代码:

function helloWorld (ready) {
    return new Promise(function (resolve, reject) {
        if (ready) {
            resolve("Hello World!");
        } else {
            reject("Good bye!");
        }
    });
}

helloWorld(true).then(function (message) {
    alert(message);
}, function (error) {
    alert(error);
});

helloWorld方法接受一个参数,如果为true 打印 Hello World!如果为false打印Good bye!;helloWorld()返回的是一个promise对象。

在promise中有两个很重的方法:resolve 和 reject;

==resolve== :可以使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操作,在这个例子当中就是 Hello World! 字符串。

==reject== :可以使 Promise 对象的状态改变成失败,同时将错误的信息传递到后续错误处理的操作。

理解Promise.resolve和理解Promise.reject

一般情况下我们都会使用new Promise()来创建promise对象,但是我们也可以使用promise.resolve 和 promise.reject这两个方法;

Promise.resolve(value)的返回值也是一个promise对象,我们可以对返回值进行.then调用;如下代码:

promise.resolve(10).then(function(value){
    console.log(value)//10
})

resolve(10)代码中,会让promise对象进入确定(resolve状态),并将参数11传递给后面的then所指定的onFulfilled 函数;

Promise.reject 也是new Promise的快捷形式,也创建一个promise对象,比如如下代码:

new Promise(function(resolve,reject){
     reject(new Error("错误!"));
});

可以变成:

Promise.reject(new Error("错误!"));

综合看看使用resolve方法和reject方法的demo如下:

function getready(ready){
  return  new Promise(function(resolve,reject){
        if(ready){
            resolve("ok")
        }else{
            reject("No");
        }
    })
    
};

getready(true).then(function(msg){
    console.log(msg)
},function(error){
     console.log(error)
})

上面的代码的含义是给getready方法传递一个参数,返回的是一个promise对象,如果为true的话,那么调用promise对象中的resolve()方法,并且把其中的参数传递给后面的then第一个函数内,因此打印出 ok, 如果为false的话,会调用promise对象中的reject()方法,则会进入then的第二个函数内,会打印No;

Promise对象的三种状态

  1. Fulfilled 可以理解为成功的状态
  2. Rejected 可以理解为失败的状态
  3. Pending 既不是 Fulfilld 也不是 Rejected 的状态,可以理解为 Promise 对象实例创建时候的初始状态

比如Promise对象中的resolve方法就是调用then对象的第一个函数,也就是成功的状态;而reject方法就是调用then对象的第二个函数,也就是失败的状态;

理解Promise异步调用的操作

如以下代码:

var promise = new Promise(function(resolve){
    console.log(1);
    resolve(3);
});
promise.then(function(value){
    console.log(value);
});
console.log(2);


//输出顺序:1 2 3

上面的代码输出结果为: 1,2,3;首先代码从上往下执行,首先输出的1,然后调用resolve(3)这个方法,这个时候,Promise变为了确定状态,即调用onFullfilled的方法,Promise.then() 成功与否都可以使用的,因此第一个函数是成功调用,但是promise 是以异步方式调用的,所以先执行,console.log(2),最后输出3

理解then()

在上面 getready()的例子当中利用了 then(onFulfilld, onRejected) 方法来执行一个任务打印 "ok",在多个任务的情况下 then 方法同样可以用一个清晰的方式完成。

function printHello (ready) {
    return new Promise(function (resolve, reject) {
        if (ready) {
            resolve("Hello");
        } else {
            reject("Good bye!");
        }
    });
}
function printWorld () {
    alert("World");
}

function printExclamation () {
    alert("!");
}

printHello(true)
    .then(function(message){
        alert(message);
    })
    .then(printWorld)
    .then(printExclamation);

上述例子通过链式调用的方式,按顺序打印出了相应的内容。then 可以使用链式调用的写法原因在于,每一次执行该方法时总是会返回一个 Promise 对象。另外,在 then onFulfilled 的函数当中的返回值,可以作为后续操作的参数,因此上面的例子也可以写成:

function printHello (ready) {
    return new Promise(function (resolve, reject) {
        if (ready) {
            resolve("Hello");
        } else {
            reject("Good bye!");
        }
    });
}
function printWorld () {
    alert("World");
}

function printExclamation () {
    alert("!");
}

printHello(true).then(function (message) {
    return message;
}).then(function (message) {
    return message  + ' World';
}).then(function (message) {
    return message + '!';
}).then(function (message) {
    alert(message);
});

//输出Hellow world!
var promise1 = new Promise(function(resolve){
    resolve(2);
});
promise1.then(function(value){
    return value * 2;
}).then(function(value){
    return value * 2;
}).then(function(value){
    console.log("1"+value);
});

打印出18,即 "1" + 222 = 18;

使用方法链的then,使多个then方法连接在一起了,因此函数会严格执行 resolve -- then --- then -- then的顺序执行,并且传递每个then方法的value的值都是前一个promise对象中return的值;因此最后的结果就是18了;

理解catch()

Promise.catch()方法是promise.then(undefined,onRejected)方法的一个别名,该方法用来注册当promise对象状态变为Rejected的回调函数。

如下代码:

var promise = Promise.reject(new Error("message"));
promise.catch(function(error){
    console.log(error.message);//message
});

现在我们再回过头一刚开始我们讨论的为什么要使用promise的原因的问题了,比如2个ajax请求,后一个ajax请求需要获取到前一个ajax请求的数据,我们之前在使用jquery写代码是如下的:

$.ajax({
    url:'a.php',
    datatype:"json",
    success:function(data){
         // 获取data数据 传给下一个请求
         var id=data.id;
         $.ajax({
             url:"b.php",
             datatype:'json',
             success:function(){
                 
             }
         })
    }
    
})

现在我们学习了then方法后,我们可以重新编写上面的代码变成如下:

var ajaxPromise = new Promise(function(resolve){
    resolve();
});
ajaxPromise.then(fucntion(){
    $.ajax({
    url:'a.php',
    datatype:"json",
    success:function(data){
         // 获取data数据 传给下一个请求
         var id=data.id;
         return id;
    }
    
})
}).then(function(id){
        $.ajax({
        url:'',
        dataType:'json',
        data:{"id":id},
        success: function(data){
            console.log(data);
        }
    });
})

理解Promise.all

Promise.all可以接受一个元素为Promise对象的数组作为参数,当这个数组里面所有的promise对象都变为resolve时,该方法才会返回。

如下代码:

var promise1 = new Promise(function(resolve){
    setTimeout(function(){
        resolve(1);
    },3000);
});
var promise2 = new Promise(function(resolve){
    setTimeout(function(){
        resolve(2);
    },1000);
});
Promise.all([promise1,promise2]).then(function(value){
    console.log(value); // 打印[1,2]
});

输出的是1,2。如上我们看到promise1对象中的setTimeout是3秒的时间,而promise2对象中的setTimeout是1秒的时间,但是在Promise.all方法中会按照数组的原先顺序将结果返回;在我们平时的需求中,或许有这种情况的需求,比如我们需要发2个ajax请求时,不管他们的先后顺序,当这2个ajax请求都同时成功后,我们需要执行某些操作的情况下,这种情况非常适合;

理解Promise.all

如上可知:Promise.all 在接收到的所有对象promise都变为FulFilled或者 Rejected状态之后才会继续后面的处理,但是Promise.race的含义是只要有一个promise对象进入FulFilled或者Rejected状态的话,程序就会停止,且会继续后面的处理逻辑;

如下代码:

// `delay`毫秒后执行resolve
function timerPromise(delay){
    return new Promise(function(resolve){
        setTimeout(function(){
            resolve(delay);
        },delay);
    });
}
// 任何一个promise变为resolve或reject 的话程序就停止运行
Promise.race([
    timerPromise(1),
    timerPromise(32),
    timerPromise(64),
    timerPromise(128)
]).then(function (value) {
    console.log(value);    // => 1
});

输出的是1,如上代码创建了4个promise对象,这些promise对象分别在1ms,32ms,64ms,128ms后变为确定状态,并且在第一个变为确定状态后1ms后,then函数就会被调用,这时候resolve()方法给传递的值为1,因此执行then的回调函数后,值变为1;

我们再来看看当一个promise对象变为确定状态(FulFiled)的时候,他们后面的promise对象是否还在运行呢?我们继续看如下代码运行:

var runPromise = new Promise(function(resolve){
    setTimeout(function(){
        console.log(1);
        resolve(2);
    },500);
});
var runPromise2 = new Promise(function(resolve){
    setTimeout(function(){
        console.log(3);
        resolve(4);
    },1000);
});
// 第一个promise变为resolve后程序停止
Promise.race([runPromise,runPromise2]).then(function(value){
    console.log(value);
});

输出的是: 1 2 3,。

如上代码是使用定时器调用的,上面是2个promise对象,我们看到第一个promise对象过500毫秒后加入到执行队列里面去,如果执行队列没有其他线程在运行的时候,就执行该定时器,所以第一次打印1,然后调用resolve(2); 接着调用promise.race方法,该方法只要有一个变为成功状态(FulFiled)的时候,程序就会停止,因此打印出2,同时后面的promise对象接着执行,因此打印出3,但是由于promise.race()该方法已经停止调用了,所以resolve(4)不会有任何输出;因此最后输出的是1,2,3;

由此我们得出结论,当一个promise对象变为(FulFilled)成功状态的时候,后面的promise对象并没有停止运行。

你可能感兴趣的:(es6 Promise的学习笔记)