前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >es6之Promise是什么「建议收藏」

es6之Promise是什么「建议收藏」

作者头像
全栈程序员站长
发布2022-09-03 14:49:49
4050
发布2022-09-03 14:49:49
举报

大家好,又见面了,我是你们的朋友全栈君。

目录

Promise的含义

Promise是一个容器,内部保存着某个未来才会结束的事件(通常是一个异步操作)的结果。Promise也是一个对象,可以通过这个对象获取异步操作的消息。 Promise的特点:

  1. 对象的状态不受外部影响,只有异步操作的结果才能决定状态。一共有三种状态:pending(进行中)、fulfilled(成功的)和rejected(失败的)。
  2. 对象的状态发生改变后,不会再变化,并且随时可以得到这个结果。对象的状态改变只有两种情况:pending=》fulfilledpending=》rejected

Promise的缺点:

  1. 无法取消Promise,一旦创建就会立即执行
  2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  3. 当对象状态是pending时,无法得知当前进行到哪一步(刚刚开始还是即将完成)。

基本用法

  1. 创建Promise实例
代码语言:javascript
复制
const promise = new Promise(function(resolve, reject){ 
   
	// ...some code
	if (/*异步操作成功*/) { 
   
		resolve(value);
	} else { 
   
		reject(error);
	}
});

Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。 resolve函数的作用:将Promise对象状态从“未完成”变为“成功”(pending=》resolved)。在异步操作成功时调用,并将异步操作的结果作为参数传递出去。 reject函数的作用:将Promise对象状态从“未完成”变为“失败”(pending=》rejected)。在异步操作失败时调用,将异步操作爆出的错误,作为参数传递出去。

  1. 调用Promise Promise实例生成后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
代码语言:javascript
复制
promise.then(function(value){ 
   
	//success Promise对象的状态变为resolved时调用
}, function(error){ 
   
	//failure Promise对象的状态变为rejected时调用,该函数为可选参数
});
  1. reject函数和resolve函数参数 reject函数的参数通常是Error对象的实例。 resolve函数的参数除了正常的值意外,还可能是另一个Promise实例。

Promise.prototype.then()

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

代码语言:javascript
复制
// 第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数,回调函数可以采用箭头函数形式,更加简洁
getJSON("/posts.json").then(function(json){ 
   
	return json.post;
}).then(function(post){ 
   
//...
});

Promise.prototype.catch()

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

代码语言:javascript
复制
getJSON("/posts.json").then(fuction(posts){ 
   
	//...
}).catch(function(error){ 
   
	// 处理getJSON 和 前一个回调函数运行时发生的错误
});

如果没有使用catch()方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。

Promise.prototype.finally()

finally()方法用于指定不管Promise对象最后状态如何,都会执行的操作。该方法是ES2018引入标准的。 finally方法的回调函数不接受任何参数,这意味着它不知道前面的Promise实例的状态,这表明,finally方法里面的操作,应该是和状态无关的,不依赖于Promise的执行结果。 finally本质上是then方法的特例。

Promise.all()

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

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

参数Promise.all()方法接收一个数组作为参数,p1、p2、p3都是Promise实例,如果不是,则调用Promise.resolve方法,将参数转化为Promise实例。 Promise.all()方法的参数可以不是数组,但必须具有Iterator接口。 新实例p的状态由p1、p2、p3决定,有两种情况

  1. fulfilled只有p1、p2、p3的状态都变成fulfilledp的状态才会变成fulfilled,此时,它们的返回值组成一个数组,传递给p的回调函数
  2. rejected只要p1、p2、p3之中有一个被rejectedp的状态就变成了rejected,此时,第一个被reject的实例的返回值,会传递给p的回调函数

注意:如果作为参数的Promise实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()catch方法。

代码语言:javascript
复制
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: 报错了]

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

Promise.race()

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

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

新实例只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。率先改变的Promise实例的返回值,就传递给p的回调函数参数:和Promise.all()方法一样,如果不是Promise实例,就会调用Promise.resolve()方法转化。

代码语言:javascript
复制
const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) { 
   
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);

p
.then(console.log)
.catch(console.error);

上面代码中,如果5秒内fetch方法无法返回结果,结果p的状态就会变为rejected,从而触发catch方法指定的回调函数。

Promise.allSettled()

Promise.allSettled()方法接收一组Promise实例作为参数,包装成一个新的Promise实例。只有等到所有这些参数实例都返回结果,无论是fulfilled还是rejected,包装实例才会结束。该方法由ES2020引入。 新实例:返回新的Promise实例,一旦结束,状态总是fulfilled,不会变成rejected。状态变成fulfilled后,Promise的监听函数接收到的参数是一个数组,每个成员对应传入一个Promise.allSettled()的Promise实例。

代码语言:javascript
复制
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) { 
   
  console.log(results);
});
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]

使用Promise.allSettled()方法可以确定所有传入的Promise实例的异步操作是否结束了。

Promise.any()

Promise.any()方法接收一组Promise实例作为参数,包装成一个新的Promise实例。 新实例新实例的状态由所有参数实例决定,有两种情况

  1. fulfilled只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled
  2. rejected如果所有参数实例都变成rejected状态,包装状态就会变成rejected状态
代码语言:javascript
复制
var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);

Promise.any([resolved, rejected, alsoRejected]).then(function (result) { 
   
  console.log(result); // 42
});

Promise.any([rejected, alsoRejected]).catch(function (results) { 
   
  console.log(results); // [-1, Infinity]
});

Promise.resolve()

Promise.resolve()方法可以把现有对象转为Promise对象。

代码语言:javascript
复制
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
  1. 参数是一个 Promise 实例 不做任何修改。
  2. 参数是一个thenable对象 thenable对象是指具有then方法的对象。如下:
代码语言:javascript
复制
let thenable = { 
   
  then: function(resolve, reject) { 
   
    resolve(42);
  }
};

转化为Promise对象,然后执行thenable对象的then方法。 3. 参数不是具有then方法的对象,或根本就不是对象

代码语言:javascript
复制
const p = Promise.resolve('Hello');

p.then(function (s){ 
   
  console.log(s)
});
// Hello

返回的Promise实例一生成就是resolved,所以回调函数会立即执行。 4. 不带有任何参数 Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的Promise对象(没有参数)。

代码语言:javascript
复制
const p = Promise.resolve();

p.then(function () { 
   
  // ...
});

Promise.reject()

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

代码语言:javascript
复制
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, function (s) { 
   
  console.log(s)
});
// 出错了

注意Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。 如果传入一个thenable对象,那回调函数的参数就是这个对象。

应用

  1. 加载图片 加载完,根据成功与否(Promise状态变化),去回调函数,进行后续操作。
代码语言:javascript
复制
const preloadImage = function (path) { 
   
  return new Promise(function (resolve, reject) { 
   
    const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = path;
  });
};
  1. Generator函数与Promise的结合

Promise.try()

需求:不区分函数f是同步函数还是异步操作,但是想用Promise来处理它。因为这样就可以不管f是否包含异步操作,都用then方法指定下一步流程,用catch方法处理f抛出的错误。 一般写法

代码语言:javascript
复制
const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');
// next
// now

一般写法缺点:如果f是同步函数,它会在本轮事件循环的末尾执行。 改进写法1

代码语言:javascript
复制
const f = () => console.log('now');
(async () => f())(); // 立即执行的匿名函数
console.log('next');
// now
// next

第二行的匿名函数立即执行里面的async函数,如果f同步就会得到同步结果,如果f异步,就可以用then指定下一步,catch捕获错误。如果不使用catch方法捕获错误,async() => f()会吃掉f()抛出的错误。 改进写法2

代码语言:javascript
复制
const f = () => console.log('now');
(
  () => new Promise(
    resolve => resolve(f())
  )
)();
console.log('next');
// now
// next

同样是立即执行的匿名函数,创建一个新的Promise实例,调用resolve方法,把f函数作为参数传入。这种情况下,同步函数也是同步执行的。 改进方法3

代码语言:javascript
复制
const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next

Promise.try()方法替代上面两种写法,为所有操作提供了统一的处理机制,还可以更好地管理异常。 管理异常: 一个Promise对象抛出异步错误,可以用catch方法捕获,如下:

代码语言:javascript
复制
database.users.get({ 
   id: userId})
.then(...)
.catch(...)

但如果该对象抛出了同步错误,就需要使用try...catch去捕获。

代码语言:javascript
复制
try { 
   
  database.users.get({ 
   id: userId})
  .then(...)
  .catch(...)
} catch (e) { 
   
  // ...
}

使用Promise.try()方法生成的实例,可以统一调用promise.catch()捕获所有同步和异步的错误。

代码语言:javascript
复制
Promise.try(() => database.users.get({ 
   id: userId}))
  .then(...)
  .catch(...)

Promise.try模拟try代码块,promise.catch模拟catch代码块。

学习资料

ECMAScript 6 入门

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/139844.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022年5月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

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