目录
导入
- 众所周知js是单线程的,一段时间内只能做一件事,这种如果遇到一个耗时操作,最常见的比如请求接口,会出现阻塞页面渲染等各种不合理情况发生,如果要避免,得单线程非阻塞,由此事件循环Event Loop走入视线中
- 异步操作同样也得依据回调函数来实现,由调用者调用,交给执行者执行的函数
- 但是回调函数会出现多层回调嵌套,回调地狱现象
- 此时Promise闪亮登场
Promise内部对外界的承诺
CommonJS社区提出,ES2015成语言规范
构造函数
新建后会立马执行
const p = new Promise((resolve, reject) => {
console.log('我来了')
resolve()
})
//我来了
接收函数作为参数
生成promise实例,并且状态一旦确定不会更改
resolve
介绍
在异步操作,操作成功后调用
功能
- pending=>fulfilled
- 将操作结果作为参数传递出去,操作结果会传递给回调函数
- 正常值
- 正常值
- Promise实例
- promise1中resolve(promise2)
- promise1的状态由promise2来决定
- 调用resolve并不会终结Promise函数的执行
- return resolve('111')就可以阻断后面的流程
reject
介绍
异步操作失败时调用
功效
- pending=>rejected
- 将异步操作报出的错误,作为参数传递出去
- 带参数
- 通常是Error的实例,表示抛出的异常,可以看promise2
- 带参数
then
为promise实例添加改变状态时的回调,返回是一个新的promise实例
- 两个参数
- 第一个参数是resolved时调用
- onFullFilled函数
- 第二个是变rejected时调用
- onRejected函数
- 两者都是可选的
-
var p1 = new Promise(function (resolve, reject) { resolve('成功'); }); p1.then(console.log, console.error); // "成功" var p2 = new Promise(function (resolve, reject) { reject(new Error('失败')); }); p2.then(console.log, console.error); // Error: 失败
- 第一个参数是resolved时调用
- 链式调用
- 前一个then方法中的回调函数,可能会返回Promise
- 等待该promise结果,再执行then或者catch
- return
- 第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
- 前一个then方法中的回调函数,可能会返回Promise
- 思考题,来看看then不同用法,摘自Promise 对象 - JavaScript 教程 - 网道
-
// 写法一 f1().then(function () { return f2(); }); // 写法二 f1().then(function () { f2(); }); // 写法三 f1().then(f2()); // 写法四 f1().then(f2);
-
catch
等价于Promise.prototype.then(null, rejection), 使用catch方法替代then中的rejection方法,promise抛出一个异常,会被该方法指定的回调函数捕获,如果该Promise状态已变成resolved,抛出异常无效
- Promise对象具有“冒泡性质”,发生异常后,一直向后传递,直到被捕获为止
- 如果不设置catch捕获异常,Promise会吃掉异常,不会阻影响外部代码
-
const promise = new Promise(function(resolve, reject) { throw new Error('test'); }); promise.catch(function(error) { console.log(error); });
finally
ES2018引入,不管最后Promise状态如何都会执行,不接受参数,其实也是then方法的特例
Promise.all()
多个promise实例包装成一个新的promise实例,接受数组作为参数,数组的中的每一个状态是fullfilled,该promise就变成resolved,执行then,否则catch
const p = Promise.all([p1, p2])
参数
- 如果数组中的某一项不是promise对象,先
Promise.resolve
方法,将参数转为 Promise 实例 - 也可以不是数组,但必须得支持Iterator 接口
- 如果该参数中Promise实例有自己的catch方法,当该实例reject的时候,会执行自己的catch方法不会执行,promise.all的catch方法
Promise.race()
与Promise.all用法基本一致,不同的是数组中有一个promise实例改变状态, p就跟着改变
const p = Promise.race([p1, p2, p3]);
Promise.allSettled()
ES2020新增,用来确定一组异步操作是否都结束了(不管成功或失败),该方法返回的新的 Promise 实例,一旦发生状态变更,状态总是fulfilled
,不会变成rejected
返回数组,集合中每一个类似结构为
{status: 'fulfilled', value: value}
{status: 'rejected', reason: reason}
Promise.any()
ES2021新增,同样也是接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。只要参数实例有一个变成fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态。
Promise.resolve()
将现有对象转换为Promsie对象,并且状态是fulfilled
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
参数形式
- 参数是一个Promise实例
- 不做任何修改,原封不懂得返回这个实例
- 参数是一个thenable对象
- 也就是具有then方法得对象,会立即执行thenable中得then方法
- 原始值或者是一个没有then()方法得对象
- 返回一个新的Promise对象,状态为resolved,并将参数传给回调函数
- 不带有任何参数,直接返回一个状态为resolved的Promise对象
-
setTimeout(function () { console.log('three'); }, 0); Promise.resolve().then(function () { console.log('two'); }); console.log('one'); // one // two // three
Promise.reject()
该方法返回一个Promise对象,状态是rejected,参数是什么,就原封不对的传给回调函数
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
总结
ok了家人们,到现在promise的就大概介绍完了,内容大概介绍了如何创建promise实例( new Promise构造函数、Promise.resolve()、Promise.reject())等、promise实例有哪些方法(then、catch使用)、Promise有哪些方法(all、race、allSettled、any)等,
强烈推荐 参考:ES6 入门教程