前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初识Promise

初识Promise

原创
作者头像
Umbrella1024
修改2021-03-26 10:25:30
5150
修改2021-03-26 10:25:30
举报
文章被收录于专栏:前端Up Up!

一、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的基本用法。

代码语言:javascript
复制
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方法。

举个栗子吧

代码语言:javascript
复制
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对象内部抛出的异常。

举个栗子:

代码语言:javascript
复制
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实例。

代码语言:javascript
复制
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的回调函数

举个栗子:

代码语言:javascript
复制
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
image

再看一个栗子:

代码语言:javascript
复制
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。

再再看一个栗子:

代码语言:javascript
复制
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实例。

代码语言:javascript
复制
var p = Promise.race([p1,p2,p3])

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

举个栗子:

代码语言:javascript
复制
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对象,状态为resolvedvar 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对象最后状态如何都会执行的操作。

举个栗子:

代码语言:javascript
复制
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的故事,敬请期待~

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Promise是啥?
  • 二、怎么使用Promise?
    • Promise.prototype.then
      • Promise.prototype.catch
        • Promise.all
          • Promise.race
            • Promise.resolve
              • Promise.reject
                • Promise.finally
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档