Promise
目的:为了更好使用Promise日常使用。
Promise概念
Promise是JavaScript的内置对象
,同时也是一个构造函数
。
特别说明:Promise构造函数是为了解决异步问题
;同步代码中也可以使用(大材小用)。
作为内置对象
静态方法
- Promise.all(iterable)
- Promise.allSettled(iterable)
- Promise.any(iterable)
- Promise.race(iterable)
- Promise.reject(reason)
- Promise.resolve(value)
作为构造函数
Promise.prototype
- Promise.prototype.constructor
- Promise.prototype.then(onFulfilled, onRejected)
- onFulfilled为可选参数
- onRejected为可选参数
- Promise.prototype.catch(onRejected)
- onRejected为可选参数
- Promise.prototype.finally(onFinally)
- onFinally为可选参数
Promise实例
const promise = new Promise(function(resolve, reject) {
// ...省略代码
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
关于executor函数、resolve函数、reject函数的说明
- Promise构造函数接受一个
executor
函数作为参数 executor
函数的两个参数分别是resolve
函数和reject
函数resolve
函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从pending
变为resolved
),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject
函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从pending
变为rejected
),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
关于then方法说明
- Promise实例生成以后,可以用
then
方法分别指定fulfilled
状态和rejected
状态的回调函数。 then
方法可以接受两个参数。- 参数可选:onFulfilled 和 onRejected 都是可选参数,不一定要提供。
- 如果
onFulfilled
不是函数,其必须被忽略 - 如果
onRejected
不是函数,其必须被忽略 - 如果
onFulfilled
是函数:- 当 promise 执行结束后其必须被调用,其第一个参数为 promise 的终值value
- 在 promise 执行结束前其不可被调用
- 其调用次数不可超过一次
- 如果
onRejected
是函数:- 当 promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因reason
- 在 promise 被拒绝执行前其不可被调用
- 其调用次数不可超过一次
then
方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
手写Promise构造函数更好理解Promise(PromiseA+标准)
特别说明:通过类实现Promise构造函数
1. 实现executor
函数、resolve
函数、reject
函数
class Promise{
// 构造器
constructor(executor){
// 成功
let resolve = () => { };
// 失败
let reject = () => { };
// 立即执行executor函数
executor(resolve, reject);
}
}
2.实现Promise构造函数基本状态(state)
- Promise构造函数三种状态
pending
(进行中)fulfilled
(已成功)rejected
(已失败)
- Promise构造函数状态切换
pending
(等待态)为初始态- 通过
resolve函数
可以转化为fulfilled
(成功态)- 成功时,不可转为其他状态,且必须有一个不可改变的值(value)
- 通过
reject函数
可以转化为rejected
(失败态)- 失败时,不可转为其他状态,且必须有一个不可改变的原因(reason)
- 若是
executor函数
报错 直接执行reject函数
- Promise构造函数几个关键属性
state
: 状态描述value
: 成功值reason
: 失败原因
class Promise{
constructor(executor){
// 初始化state为等待态(state状态只能改变一次)
// 因为只有状态为pending时候可以改变
this.state = 'pending';
// 成功初始值
this.value = undefined;
// 失败原因初始值
this.reason = undefined;
// resolve函数、reject函数
const resolve = (value) => {
// 如果state不为pending,下面条件为false,块级作用域代码不再执行
if (this.state === 'pending') {
// resolve调用后,state转化为fulfilled成功态
this.state = 'fulfilled';
// 更新成功的值
this.value = value;
}
};
const reject = (reason) => {
// 如果state不为pending,下面条件为false,块级作用域代码不再执行
if (this.state === 'pending') {
// reject调用后,state转化为rejected失败态
this.state = 'rejected';
// 更新失败的原因
this.reason = reason;
}
};
// 如果executor执行报错,直接执行reject函数,错误信息作为入参传给reject函数
try{
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
}
3.实现Promise实例的then方法(Promise.prototype.then)
- then的方法接收两个参数(可选):
onFulfilled
函数和onRejected
函数 onFulfilled
函数的参数为成功值value
onRejected
函数的参数为失败原因reason
executor函数同步执行
class Promise{
constructor(executor){
// ...省略代码
}
// then方法有两个参数onFulfilled函数和onRejected函数
then(onFulfilled,onRejected) {
// 状态为fulfilled,执行onFulfilled函数,传入成功的值
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
// 状态为rejected,执行onRejected函数,传入失败的原因
if (this.state === 'rejected') {
onRejected(this.reason);
};
}
}
executor函数在异步中调用resolve函数或reject函数
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// onFulfilled函数回调数组
this.onResolvedCallbacks = [];
// onRejected函数回调数组
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 一旦resolve执行,调用onFulfilled函数回调数组
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 一旦reject执行,onRejected函数回调数组
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
if (this.state === 'rejected') {
onRejected(this.reason);
};
// 当状态state为pending时
if (this.state === 'pending') {
// onFulfilled函数传入onFulfilled函数回调数组
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected传入onRejected函数回调数组
this.onRejectedCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
}
-
上述代码同时实现了
同一个
promise实例被多个then调用问题// 多个then的情况 const p = new Promise(); p.then(); p.then();
4.实现Promise实例的链式调用
调用Promise构造函数原型对象的then、catch、finally都返回新的promise实例
class Promise{
constructor(executor){
// ...省略代码
}
then(onFulfilled,onRejected) {
// 返回的promise2
const promise2 = new Promise((resolve, reject)=>{
if (this.state === 'fulfilled') {
const x = onFulfilled(this.value);
// resolvePromise函数,处理onFulfilled函数return的x和默认的promise2的关系
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'rejected') {
const x = onRejected(this.reason);
// resolvePromise函数,处理onRejected函数return的x和默认的promise2的关系
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(()=>{
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.onRejectedCallbacks.push(()=>{
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
})
}
});
// 返回promise,完成链式
return promise2;
}
}
resolvePromise函数实现
- 如果
promise
和x
指向同一对象(x === promise2
),会造成循环引用,自己等待自己完成,则报“循环引用”错误以 TypeError 为据因拒绝执行 promise
const p = new Promise(resolve => {
resolve('success');
});
const p1 = p.then(data => {
// 循环引用,自己等待自己完成,一辈子完不成
return p1;
})
- 比较x和promise2,避免循环应用
- 如果
x== null
或typeof x !== 'object'
或typeof x !== 'function'
直接resolv(x)
- 如果
x != null && (typeof x === 'object' || typeof x === 'function')
- x不是promise,直接
resolv(x)
- x是promise直接调用then方法
- x不是promise,直接
function resolvePromise(promise2, x, resolve, reject){
// 循环引用报错
if(x === promise2){
// reject报错
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 防止多次调用
let called;
// x不是null 且x是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+规定,声明then = x的then方法
const then = x.then;
// 如果then是函数,就默认是promise了
if (typeof then === 'function') {
// 就让then执行第一个参数是this后面是成功的回调和失败的回调
// then方法中this指向x
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// resolve的结果依旧是promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);// 失败了就直接执行reject函数
})
} else {
resolve(x); // 直接成功即可
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
// 取then出错了那就不要在继续执行了
reject(e);
}
} else {
resolve(x);
}
}
5.完善then方法中onFulfilled函数和onRejected函数
- 1、PromiseA+规定onFulfilled,onRejected都是可选参数,如果他们不是函数,
必须被忽略
。- onFulfilled是一个普通的值,成功时直接等于 value => value
- onRejected返回一个普通的值,失败时如果直接等于 value => value,则会跑到下一个then中的onFulfilled中,所以直接扔出一个错误reason => throw err
- 4、PromiseA+规定onFulfilled或onRejected不能同步被调用,必须异步调用。我们就用setTimeout解决异步问题
- 5、如果onFulfilled或onRejected报错,则直接返回reject()
class Promise{
constructor(executor){
// ...省略代码
}
then(onFulfilled,onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
// 异步
setTimeout(() => {
// 如果报错
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
// 返回promise,完成链式
return promise2;
}
}
6.实现catch和resolve、reject、race、all方法
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
return promise2;
}
// catch方法
catch(fn){
return this.then(null,fn);
}
}
function resolvePromise(promise2, x, resolve, reject){
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
if(called)return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, err => {
if(called)return;
called = true;
reject(err);
})
} else {
resolve(x);
}
} catch (e) {
if(called)return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
//resolve方法
Promise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
});
}
//reject方法
Promise.reject = function(val){
return new Promise((resolve,reject)=>{
reject(val)
});
}
//race方法
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject)
};
})
}
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
Promise.all = function(promises){
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
i++;
if(i == promises.length){
resolve(arr);
};
};
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data);
},reject);
};
});
}
Promise配合async/await使用
let result = true;
// 从服务器接口获取数据
async function getServerData(){
// 模拟请求
const p = new Promise((resolve,reject)=>{
setTimeout(() => {
if(result){
resolve('data')
}else {
reject('err')
}
}, 1000);
})
return p
}
// 供前端调用接口
async function dataController() {
try {
const data = await getServerData();
console.log('data',data);
} catch (error) {
// 可以捕获reject
console.log('error', error);
}
}
// 前端接口
dataController()
- 特别说明
try...catch
中catch
可以捕获reject
函数的reason
参考文章
BAT前端经典面试问题:史上最最最详细的手写Promise教程
关于Generator函数
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!