初识Promise

一、Promise是啥?

Promise是异步编程的一种优雅的解决方案。它相比于回调和事件交互,更加合理和强大。它改善了深度回调的问题。 回调里面还有回调,层级较深的,代码看起来特别凌乱。而通过事件交互会多做一些工作,比如发送事件,监听事件,事件回调等操作。而Promise能够获取异步操作的结果,这样的话,方便进一步处理接下来的逻辑。

Promise,简单来说,他就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。ES6将其写进了语言标准,并原生提供了Promise对象。

Promise的特点

  1. 对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:Pending(进行中)、FulFilled(已成功)和Rejected(已失败),任何其他操作都无法改变这个状态。这也就是“Promise”这个名字的由来,它在英文中意思为“承诺”,表示其他手段无法改变。
  2. 一旦状态改变就不会再变。任何时候都可以得到这个结果。Promise对象的状态改变只有两种可能:从Pending到Fulfilled,或者从Pending到Rejected。只要这两种情况发生,状态就不会再改变。

有了Promise对象,就可以将异步操作以同步操作的流程表达出来。避免了层层嵌套的回调。此外Promise对象还对外提供了统一的接口,使控制异步操作更加容易。

Promise也有一些缺点,它一旦开始他就会立即执行,并且无法取消。这个很Promise!

其次,如果不设置回调函数,Promise内部的异常不会反应到外部,也就是说内部出错了也不知道。再者,当处于Pending状态时,无法得知目前进展到哪一步,是刚刚开始,还是即将完成

二、怎么使用Promise?

ES6规定,Promise对象是一个构造函数,用来生成Promise对象。
下面的代码反映了Promise的基本用法。

var promise = new Promise(function(resolve,reject){
    //some code
    if(操作成功){
        resolve(value);
    }else{
        reject(error);
    }
})

Promise的构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject,他们是两个函数,是由JavaScript引擎提供,不用开发者自己部署。

resolve的作用是,将Promise从未完成(Pending)状态变成已成功(Fulfilled)状态,在异步操作成功时调用,并把异步操作的结果作为参数传递出去。
reject的作用是将Promise从未完成(Pending)状态变成已失败(Rejected)状态,在异步操作失败时调用,并把异步操作的错误作为参数传递出去。

Promise.prototype.then

Promise实例具有then方法,then方法是定义在Promise.prototype上的,它的作用是为Promise实例添加状态回调改变时的回调函数。then的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态下的回调函数。then方法返回的是一个新的Promise对象。注意,不是原来的那个Promise对象,因此可以采用链式写法,即then方法后面还可以再调用then方法。

举个栗子吧

let promise = new Promise((resolve, reject) => {
    console.log("Promise!");
    resolve();
    console.log("Promise Over");
})

setTimeout(() => {
    console.log("Hello World!");
}, 0)

console.log("Hi!");

promise.then(() => {
    console.log("Resolved!");
})

运行截图如下:
运行截图

我们来分析下运行结果:
promise一旦被创建,就会立即执行,那么代码同步执行,首先就会输出Promise,接下来就会输出Promise Over;因为Promise一系列的操作(then、catch)优先级比setTimeout要高,然后在执行Promise.then,所以接下来是输出Resolved!,最后执行setTimeout,输出Hello World。

Promise.prototype.catch

Promise.prototype.catch方法是.then(null,reject)的别名,用于指定发生错误的回调。catch可以捕捉到在它之前所有的promise对象内部抛出的异常。

举个栗子:

var doSomething = () => {
    return new Promise((resolve, reject) => {
        console.log("doSomething");
        resolve(1 + x);
        console.log("doSomething over");
    })
}

doSomething().then((value) => {
    console.log(value)
}).catch((err) => {
    console.log("hhhhhh");
    console.log(err);
})

运行截图如下:
运行截图

Promise.all

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

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

上面代码中,Promise.all方法接受一个数组作为参数,p1、p2、p3都是Promise对象的实例,如果不是,就会先调用下面讲到的Promise.resolve方法, 将参数转为Promise实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例。)

p的状态由p1、 p2、 p3决定, 分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、 p2、 p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值, 会传递给p的回调函数

举个栗子:

let promise1 = new Promise(resolve => {
    console.log("promise1");
    resolve(1);
})

let promise2 = new Promise(resolve => {
    console.log("promise2");
    resolve(2);
})

let promise3 = new Promise(resolve => {
    console.log("promise3");
    resolve(3);
})

let promises = [promise1, promise2, promise3];

Promise.all(promises).then(value => {
    console.log(value);
}).catch(err => {
    console.log(err);
})

运行截图:
image

再看一个栗子:

let promise1 = new Promise(resolve => {
    console.log("promise1");
    resolve(1);
})

let promise2 = new Promise(resolve => {
    console.log("promise2");
    resolve(2);
})

let promise3 = new Promise(resolve => {
    console.log("promise3");
    resolve(x + 3);
}).then((value) => {
    console.log(value);
})


let promises = [promise1, promise2, promise3];

Promise.all(promises).then(value => {
    console.log(value);
}).catch(err => {
    console.log("promise all err:", err);
})

运行截图:
运行截图

分析:
在上面的代码中,promise1、promise2都正常变为resolved状态,promise3中会发生错误,状态变为Rejected。导致Promise.all这个Promise也会变为Rejected状态。所以会执行Promise.all后面的catch方法,所以在打印promise1,promise2,promise3之后,还会打印promise all err。

再再看一个栗子:

let promise1 = new Promise(resolve => {
    console.log("promise1");
    resolve(1);
})

let promise2 = new Promise(resolve => {
    console.log("promise2");
    resolve(2);
})

let promise3 = new Promise(resolve => {
    console.log("promise3");
    resolve(x + 3);
}).then((value) => {
    console.log(value);
}).catch((err) => {
    console.log("promise3 err:", err);
})


let promises = [promise1, promise2, promise3];

Promise.all(promises).then(value => {
    console.log(value);
}).catch(err => {
    console.log("promise all err:", err);
})

运行截图:
运行截图

分析:promise1,promise2都会进入resolved状态,到了promise3,promise3中有错误,那么会执行promise3后面的catch方法,而catch方法会返回一个新的Promise实例,promise3指向了这个新的promise实例。这个实例在执行完catch之后,也会变成resolved的状态。所以promise1、promise2、promise3都进入了resolved状态,那么Promise.all会执行后面的then方法,但是promise1,promise都有返回值,promise3没有返回值,所以打印出来是[1,2,undefined]。

Promise.race

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

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

上面代码中, 只要p1、 p2、 p3之中有一个实例率先改变状态, p的状态就跟着改变。 那个率先改变的Promise实例的返回值, 就传递给p的回调函数。
Promise.race方法的参数与Promise.all方法一样, 如果不是Promise实例, 就会先调用下面讲到的Promise.resolve方法, 将参数转为Promise实例,
再进一步处理。

举个栗子:

let promise1 = new Promise(resolve => {
    console.log("promise1");
    resolve(1);
})

let promise2 = new Promise(resolve => {
    console.log("promise2");
    resolve(2);
})

let promise3 = new Promise(resolve => {
    console.log("promise3");
    resolve(3);
})

let promises = [promise1, promise2, promise3];

Promise.race(promises).then(value => {
    console.log(value);
}).catch(err => {
    console.log(err);
})

运行截图:
运行截图

Promise.resolve

Promise.resolve的作用就是将一个对象转换成Promise对象。

Promise.resolve方法的参数分成为以下4种情况。

  1. 参数是一个Promise实例
    如果参数是Promise实例,那么Promse.resolve将不做任何修改,原封不动的返回这个实例。
  2. 参数是一个thenable对象
    thenable对象指的是具有then方法的对象。比如下面这个对象
    let thenable = {
        then:function(resolve,reject){
            resolve(12);
        }
    }
    
    let p = Promise.resolve(thenable);
    p.then((value)=>{
        console.log(value);
    })
    
    Promise.resolve方法会将这个对象转换成Promise对象,然后立即执行thenable对象的then方法。
    所有上面的代码,结果会输出12。
  3. 参数不是具有then方法的对象或者根本不是对象
    如果参数是一个原始值,或者是一个不具有then方法的对象,那么Promise.resolve会返回一个新的Promise对象,状态为resolved
    var p = Promise.resolve("Hello");
    p.then((s)=>{
        console.log(s)
    })
    
    上述代码会输出Hello。
  4. 不带有任何参数
    Promise.resolve允许在调用时,不带任何参数。而直接返回一个Resolved状态的Promise对象。
    需要注意,立即resolve的Promise对象是在本轮事件循环结束时么不也是下一轮事件循环开始时。
    举个栗子:
    setTimeout(() => {
        console.log("xxxx");
    }, 0);
    
    Promise.resolve().then(() => {
        console.log("yyyyy");
    })
    
    console.log("zzzz");
    
    运行截图:
    运行截图

Promise.reject

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

Promise.finally

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

举个栗子:

let p2 = new Promise((resolve, reject) => {
    resolve(1);
})

p2.then((value) => {
    console.log(value);
}).catch((err) => {
    console.log("error:", err);
}).finally(() => {
    console.log("finally");
})

输出:
1
finally

那么,Promise,你熟悉它了吗?后面还会有关于Promise的故事,敬请期待~

如有错漏,欢饮大佬们拍砖~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值