ECMAScript 6 (3)Promise 对象

Promise 对象

序、看图说话

在这里插入图片描述
在这里插入图片描述

1、Promise的含义

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

简单来说:

  1. 主要用于异步计算
  2. 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
  3. 可以在对象之间传递和操作promise,帮助我们处理队列

2、promise的作用

  • 主要是解决地狱回调的问题

开发过程中我们有时会需要请求很多个接口,这些接口的参数需要另外一个接口返回的数据作为依赖,这样一来就需要我们一层嵌套一层,最后都不知道代码执行到哪一步,导致我们的代码可读性变差,出现问题不好调试也会导致性能下降。

// 第一轮请求
http.get('some_url', function (id) {
    //do something
    // 第二轮请求
    http.get('getNameById', id, function (name) {
        //do something
        // 第三轮请求
        http.get('getCourseByName', name, function (course) {
            //dong something
            // 第四轮请求
            http.get('getCourseDetailByCourse', function (courseDetail) {
                //do something
            })
        })
    })
});

上面代码表示,第一轮的请求是获取用户 id,再通过id获取用户名,然后通过用户名获取选中课程,最后通过课程获取课程信息。如此一来代码非常繁琐,让人很不舒服。

  • 为了避免界面(任务)卡顿(暂停)

同步: 假设我们去了一家饭店,找个位置,叫来服务员,这时服务员对我们说,对不起我是“同步”服务员,我要服务完这张桌子的客人才能招呼你。那桌客人明明已经吃上了,我们只是想要个菜单,这么小的动作,服务员却要等到别人的一个大动作完成之后,才能再来招呼你,这个便是同步的问题:也就是“顺序交付的工作ABC,必须按照ABC的顺序完成”。这一系列操作如同游戏闯关,需一步一步走,绝不可能跳过中间哪一环节而执行下一个环节。

异步: 将耗时很长的A交付的工作交给系统之后,就去继续做B交付的工作, 等到系统完成了前面的工作之后,再通过回调或者事件,继续做A剩下的工作。AB工作的完成顺序,和交付他们的时间顺序无关,所以叫“异步”。

3、Promise的本质

分离了异步数据获取和业务逻辑

4、Promise 的状态

Promise 可以分为四个状态:

  • Pending:初始状态,异步操作仍在进行中。
  • Fulfilled:操作成功,它调用.then回调,例如.then(onSuccess)
  • Rejected: 操作失败,它调用.catch.then的第二个参数(如果有)。例如.catch(onError).then(..., onError)
  • Settled:这是 promise 的最终状态。promise 已经死亡了,没有别的办法可以解决或拒绝了。.finally方法被调用。

5、Promise的特点

  • 对象的状态不受外界影响。只有异步操作的结果可以决定当前时哪一种状态(pending(进行中)、fulfilled(已成功)和 rejected(以失败)),任何其他操作都无法改变这个状态。这也是promise这个名字的由来,他的英语意思就是‘承诺’,表示其他手段无法改变。

  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。

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

6、Promise的缺点

  • 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

7、Promise的基本用法

  1. 声明一个函数,让这个函数返回一个promise实例
let setPromise = function () {
	return new Promise ()
}
  1. Promise构造函数接受一个函数作为参数,并且该函数有两个参数分别是resolvereject,它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
let setPromise = function () {
	return new Promise ( (resolve,reject) => {
		 if (/* 异步操作成功 */){
		    resolve(value);
		  } else {
		    reject(error);
		  }
    })
}

8、Promise的语法

new Promise((resolve, reject) => {
    if (异步成功后) {
        resolve(value)   //将Promise的状态由padding改为fulfilled
    } else {
        reject(error)    //将Promise的状态由padding改为rejected
    }
}).then(value => {
    // resolve回调 
}, error => {
    // reject回调
})

上面的代码表示,如果异步成功后就会调用.then()里面的第一个参数方法,否则就会调用.then()里面的第二个参数方法。如果调用resolvereject时有参数,则会将参数分别传递给回调函数(.then里面的第一个和第二个参数方法)。

9、Promise的基本api

  • Promise.resolve() ⇒ 是在异步操作完成时应调用的回调

  • Promise.reject() ⇒ 是发生错误时要调用的回调函数

  • Promise.prototype.then() ⇒ 为 Promise 实例添加状态改变时的回调函数

  • Promise.prototype.catch() ⇒ 用于指定发生错误时的回调函数

  • Promise.all() ⇒ 将多个 Promise 实例,包装成一个新的 Promise 实例

  • Promise.race() ⇒ 竞速,完成一个即可

9.1 .then()方法

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。(promise 实例中使用.then方法时,可以在Promise “完成” 时得到通知。)

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

.then()方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。其中,第二个函数是可选的,不一定要提供。它的返回的是一个新的Promise实例。因此可以采用链式写法。

Promise.resolve()
  .then(a)
  .then(b)
  .then(c)
  .then(d)
  .catch(console.error);

promise的中文翻译是‘承诺’,then的中文翻译是‘ (指将来) 到那时,届时’,所以我们可以这样理解,比如我们买一样东西时正好缺货,服务员承诺(promise)我们,只要店里一来货,那时(then)将通知我们是一个道理。

9.2 .catch()方法

用于指定发生错误时的回调函数,最好是在.then()的链式调用最后调用一下此方法来捕获异常。它的返回值仍然是个Promise对象。

new Promise((resolve, reject) => {
    throw new Error('出现错误了')
}).then(value => {

}).catch(error=>{
    console.log(error)
})

上面代码中如果Promise对象状态变为resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。

如果 Promise 状态已经变成resolved,再抛出错误是无效的。

new Promise((resolve, reject) => {
    resolve('data')
    throw new Error('出现错误了')
}).then(value => {
    console.log(value)
}).catch(error=>{
    console.log(error)
})

这时不会运行catch()里面的方法。

9.3 .finally()方法

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
finally本质上是then方法的特例。如下代码是等效的:

promise
.finally(() => {
  // 语句
});
// 等同于
promise
.then(
  result => {
    // 语句
    return result;
  },
  error => {
    // 语句
    throw error;
  }
);

9.4 .all()方法

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

const p = Promise.all([p1, p2, p3])
  1. p1、p2、p3都为Promise实例,如果不是,调用Promise.resolve将它们转成Promise实例。

  2. p的状态由p1,p2,p3共同决定如果它们的状态全都为fulfilled则p的状态变成fulfilled,此时p1,p2,p3的返回值组成一个数组传递给p的回调

  3. 若p1,p2,p3中只要有一个为rejected,则p的状态变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

  4. 若p1,p2,p3自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));

// ["hello", Error: 报错了]

上面代码中,p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。如果p2没有自己的catch方法,就会调用Promise.all()的catch方法。

9.5 race()方法

此方法和Promise.all()一样接收多个Promise实例,返回一个新的Promise实例。

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

和Promise.all()的不同之处是只要p1、p2、p3中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

9.6 .resolve()方法

Promise.resolve()的作用是将现有对象转换成Promise对象。
以下的写法是等效的:

Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

resolve()参数的4种情况

  • 参数是一个 Promise 实例

这种情况Promise.resolve()什么都不做。

  • 参数是一个thenable对象

参数是具有then方法的对象(thenable对象),Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法。例如:

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。

  • 参数是普通对象或原始值

Promise.resolve返回一个状态为resolved的对象

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

// 因为p的状态为resolved所以.then()会立即执行
p.then(function (s){
 console.log(s)
});

// Hello
  • 不带任何参数

这种情况直接返回状态为resolved的Promise对象。如果希望得到一个 Promise 对象,比较方便的方法就是直接调用。
立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。示例:

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');
// one
// two
// three

上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log(‘one’)则是立即执行,因此最先输出。

9.7 reject()方法

返回状态为rejected的Promise对象。
以下两种写法等效:

const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => {
    reject('出错了')
})

p.catch(error=>{
    console.log(error)
})
// 出错了

参考文档有:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值