ES6 快查手册

ES6 - Promise

2019-03-29  本文已影响0人  爱绑架的猫

什么是 Promise?

Promise 是异步编程的一种解决方案,简单来说,就是一个容器,里面保存着一个某个未来才会结束的事件,从语法上说,Promise 是一个对象,从它可以获取异步操作的消息, Promise提供统一的 API,各种异步操作都可以用同样的方法进行处理。

特点:

1,对象的状态不受外界影响

2,一旦状态受改变,就不会改变

基础用法

创建 Promise 实例:

const promise = new Promise(function(resolve,reject){
    // this is your code
    if(/*异步操作成功*/) {
        return resolve(value);   
    }else {
        return reject(error);
    }
});

resolve 函数作用:

把 Promise 对象状态变为 成功,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。

reject 函数作用:

把 Promise 对象状态变为失败,在异步操作失败时调用,并将异步操作的结果做为参数传递出去。

这里提示: 在 Promise 实例中,调用 resolve 或者 reject 之后并不会打断后续代码的执行,所以这里我们推荐使用 "return resolve()/return reject()" 直接把 resolve/reject 返回,而不是直接 resolve()/reject() 这样可以保证 resolve() / reject() 后面的代码不会执行。

在 Promise 实例生成之后可以使用 .then 方法指定 resolved 和 rejected 的回调函数

promise.then(function(value){
   // 异步操作成功之后的 code  
},function(error){
   // 异步操作失败之后的 code
});

Promise 实例的几种特别情况

1,resolve 返回的是另一个 promise 实例

const p1 = new Promise(function(resolve,reject){
    return resolve();
})

const p2 = new Promise(function(resolve,reject){
    return resolve(p1);
})

p2.then(funciton(vlaue){
    console.log('p1 成功了');
},function(error){
    console.log('p2 失败了')
})

这里 我们 p2 这个 promise 实例中 resolve() 返回的是 p1,另一个 promise 实例,这时决定 p2 的回调成功方法是否会被调用的条件就是 p1 的回调结果了,如果 p1 成功 ,那么 p2 的回调会被立即执行,也就是 打印 ‘p1 成功’,否则执行 'p2' 失败。

.catch() 方法

Promise.prototype.catch方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

const promise = new Promise(function(resolve,reject){
    if(false == true){
         console.log(x + 2); // 这里有错误,x 未定义
        return resolve(value);  
    }else {
        return reject(error);
    }
});

promise.then(function(value){
    console.log('成功!');
}).catch(function(error){
    console.log(error)
})

这里我们推荐用 .catch() 方法代替 .then(f1(){},f2(){}) 中的 f2() 也就是 reject() 的回调方法,因为 .catch() 不光可以代替 f2 ,还可以捕捉到 promise 中的错误,也就是说,x 未定义这个错误 .catch() 方法是可以捕捉到的,而 f2() 是做不到的,而且这种写法更像同步的代码逻辑。

.finally() 方法

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

prmise
.then(res=>{})
.catch(error=>{})
.finally(()=>{});

这里需要注意 finally 方法是无法接收参数的,也就是说它无法判断当前 prmise 实例的最终状态是 resolve 还是 reject ,适合把一些在 resolve 和 reject 回调方法里面都需要执行的代码提取出来,放到 finally 里面中,这样就可以减少代码行数。

.all() 方法

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

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

其中,p1,p2,p3 都是 Promise 实例,然后 p 的状态由 p1,p2,p3 决定,有两种情况:

1,p1,p2,p3 全部 resolved 这样 p 才可以 resolved 然后 p1,p2,p3 返回的值组成一个数组返回给 p 的回调函数。

2,p1,p2,p3 中一旦有一个或者多个 rejected 那么 p 的状态也变为 rejected 然后第一个 rejected 实例把返回的值

给 p 的回调函数。

总结起来就像事务的原理一样,.all() 方法具有原子性,要么都成功,要么失败。

这里需要注意,如果 .all() 中的 promise 实例某一个有自己的 .catch() 方法,并且这个 .catch() 返回的又是一个 promise 实例,这时候,这个 promise 对象如果 rejected 的话,它的最终状态是由它的 .catch() 中的这个 promise 实例的状态决定。

const p1 = new Promise((resolve,reject)=>{
    return reject(erro);
}).catch((erro)=>{
    return Promise((resolve,reject)=>{
        return resolve();
    })
})

const p2 = new Promise((resolve,reject)=>{
    resolve()
})

const p = Promise.all([p1,p2]);  // 这里 p1 的状态由 .catch 中的 Promise 决定
p.then((value)=>{
    console.log('success')
}).catch((error)=>{
    console.log(error)
})

.race() 方法

Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

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

.race() 方法与 .all() 方法不同的是,.race() 是根据 [p1,p2,p3,........] 实例数组中第一个发生变化的 promise 实例状态所决定的,假设 p1 实例先返回一个 resolved 状态,或者 rejected 状态,那么 p 的状态也会发生变化,和 p1 的状态相同,然后调用对应的回调函数。

.resolve() 方法

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

const p = Promise.resolve('foo');

这里 resolve() 的参数有三种情况:

1,Promise 实例

如果参数是一个 promise 实例,那么 resolve 将不会做任何操作,会直接把 promise 实例返回。

2,有 then() 方法的对象

let obj = {
    then: function(resolve,reject) {
        resolve(1); 
    }
}
// 这里 Obj 就是带有 then() 方法的对象
const p = Promise.resolve(obj);
p.then(function(value){
    console.log(value); // 这里 vlaue 的值是 1
})
// 这里 Promise.resolve() 会立即执行 obj 的 then 方法,然后状态更改为 resolved,然后直接调用 p 的 then 方法打印 value 的值

3,没有 then() 方法的对象或者不是对象

const p = Promise.resolve('hello world!');
p.then((value)=>{
    console.log(value); // value = hello world!
})

这里 resolve() 方法的参数是 ‘hello world!’ 这个字符串,不是带有 then 方法的对象,所以直接转换成一个 promise 实例,并且这个 promis 实例的状态是 resolved ,所以直接执行 p.then() 方法,'hello world!' 会做为参数传送给 p.then() 方法。

4,不带有任何参数

const p = Promise.resolve();
p.then(()=>{})

如果 resolve() 方法中没有传递任何参数的话,那么将会直接返回一个 resolved 状态的 promise 实例

.reject() 方法

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

const p = Promise.reject('出错了!');
p.catch((error)=>{
    console.log(error); // 出错了!
})

这里 reject() 方法的参数会原封不动的传递出去,而不会做什么改变,这与 resolve() 方法不同,例如:

let p = {
    then: function(resolve,reject) {
        reject('出错了!')
    }
}
const p1 = Promise.reject(p);
p1.catch((error)=>{
    console.log(error); // 这里 error 是 p 这个对象,而不是 '出错了' 这个参数
})

.try() 方法

在项目开发中,我们可能会碰到这样的情况,不管是同步的代码还是异步的代码都想用 Promise 封装起来,但是这样会出现一些问题,例如:

let f = function(){
    console.log('now');
}
Promise.resolve().then(f);
console.log('next');
// 执行顺序 先 next 后 now,这是因为放到 promise 里面之后就成了异步操作,会在本轮事件的末尾执行,但如果这是一个同步方法,这显然是不合理的

让我们使用 try() 改造一下:

let f = () => console.log('now');
Promise.try(f);
cosolog.log('next');
// 执行顺序,now,next

这样同步方法也会同步执行。

上一篇 下一篇

猜你喜欢

热点阅读