“这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战”
promise
可以说是现在面试必出的知识点之一,这不也快到了金九银十的招聘季了嘛,就趁着这段时间,好好的复习一下知识点。
promise
promise
是一个对象,代表了一个异步操作的最终完成或者失败。它的出现使异步操作可以像同步操作一样进行处理。
promise的状态
promise
有三种状态,而且,它的状态必然处于三种状态中的其中一种。
status | meaning |
---|---|
pending | 初始状态,既没有成功,也没有失败 |
fulfilled | 成功状态 |
rejected | 失败状态 |
默认情况下,promise
的状态处于 pending
,然后根据异步操作的状态来改变当前的状态,一旦状态发生了改变,那么就不会在发生改变了。而且,promise
的状态改变只有以下两种可能:
- 从
pending
变为fulfilled
- 从
pending
变为rejected
Promise的基本用法
在使用 Promise
的时候,我们会在里面传入一个函数,如下:
const promise = new Promise((resolve, reject) => {});
复制代码
这个函数是当 Promise
实例被创建出来后,就立即执行的,同步的哦~
console.log('1');
const promise = new Promise((resolve, reject) => {
console.log('2');
});
console.log('3');
// 1
// 2
// 3
复制代码
这个函数中,有两个参数,resolve
和 reject
。
functionName | meaning |
---|---|
resolve |
是一个函数,当异步操作成功时调用,并且把异步操作成功后的结果作为参数传入 resolve , 此时 Promise 的状态会从 pending 变为 fulfilled |
reject |
是一个函数,当异步操作失败是调用,并且把失败的错误信息或报错信息作为参数传入 reject ,此时 Promise 的状态会从 pending 变为 rejected |
手写部分①——控制MyPromise的状态
从上面的理解,我们开始手写自己的 MyPromise
:
// promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise{
status = PENDING; // Promise的默认状态
value = null; // Promise的默认值
// fn 就是我们在 new Promise时传入的那个函数,那个函数是立即执行的
// fn 中有两个函数作为参数,
constructor(fn) {
// 成功时调用,并且把状态从 pending 变成 fulfilled
const resolve = value => {
// 因为 Promise 只能在状态为 pending 的时候改为 fulfilled 或者是 rejected,并且改完之后,状态永远不能修改,所以只有当前状态为 pending 时才可以继续执行下面的操作。
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
}
};
// 失败时调用,并且把状态从 pending 变成 rejected
const reject = reason => {
if(this.status === PENDING) {
this.status = REJECTED;
this.value = reason;
}
};
fn(resolve, reject);
}
}
复制代码
测试
// 1. 是否可以改变 MyPromise 的状态
const promise = new MyPromise((resolve, reject) => {
resolve(123);
});
console.log(promise); // MyPromise {status: "fulfilled", value: 123}
// ---
const promise = new MyPromise((resolve, reject) => {
reject(123);
});
console.log(promise) // MyPromise {status: "rejected", value: 123}
// 2. 当函数内抛出错误时,能否继续运行
// Promise当遇到错误后,会继续执行后面的代码,并且把状态改为rejected,
const promise = new MyPromise((resolve, reject) => {
throw new Error('错误');
});
console.log(promise);
// 直接报错,而且没有输出 promise 的值,这是个问题,我们来修改一下
复制代码
// 省略部分代码...
class MyPromise{
// 省略部分代码...
constructor(fn) {
// 省略部分代码...
// fn(resolve, reject) 把这行代码,修改成下面这样的
// 用 try...catch...捕获错误,当有错误时,执行 reject 函数,把 Promise 的状态改为 rejected,并且把错误信息传入 reject 函数中作为参数
try{
fn(resolve, reject);
}catch(err){
reject(err);
}
}
}
复制代码
继续测试
// 当函数内抛出错误时,能否继续运行
const promise = new MyPromise((resolve, reject) => {
throw new Error('错误');
});
console.log(promise); // MyPromise {status: "rejected", value: Error: 错误 at http://127.0.0.1:5500/demo.js:33:11 at new MyPromise (http://127.0.0.1:5500/de…}
复制代码
现在,就算是执行时抛出了错误,也会继续运行下去。并且状态是为 rejected
的!
Promise.then
then()
方法主要是用于处理 Promise
状态发生改变后的回调函数,并且会返回一个新的 Promise
。
注:then
里面的函数是异步调用的,不是同步的。
它有两个 可选
参数:
functionName | meaning |
---|---|
onFulfilled |
当 Promise 的状态变成 fulfilled 时调用该函数。该函数有一个参数,用于接受成功后的结果;如果这个参数不是一个函数,则会在内部被替换为 x => x ,就是原样的返回 Promise 的最终结果。 |
onRejected |
当 Promise 的状态变成 rejected 时调用,该函数有一个参数,用于接受失败的原因;如果这个参数不是一个函数,则会在内部替换为 throw 函数。 |
then()
返回的值规则如下:
要看更详细的,请点击promise.prototype.then()
- 返回的是一个值的话,那么
then
返回的Promise
会变为fulfilled
,并且将返回值作为onFulfilled
的参数 - 没有返回任何值的话,那么
then
返回的Promise
会变为fulfilled
,并且将undefined
作为onFulfilled
的参数 - 抛出一个错的话,那么
then
的返回的Promise
会变为rejected
,并且抛出的错误信息作为onRejected
的参数 - 返回一个
Promise
的话,那么then
返回的Promise
状态是根据那个Promise
的状态决定的,并且调用的函数参数和那个Promise
变为最终状态后的回调函数的参数是一样的。
Promise.then() 的基本用法
const promise = new Promise((resolve, reject) => {
resolve(123);
});
promise.then(res => {
console.log(res); // 123
});
// -----
const promise = new Promise((resolve, reject) => {
reject(234);
});
promise.then(res => {
console.log('成功', res);
}, err => {
console.log('失败', err); // 失败 234
});
// -----
const promise = new Promise((resolve, reject) => {
resolve(123);
}).then(res => {
console.log(1, res);
}).then(res => {
console.log(2, res);
}, err => {
console.log(1, err);
}).then(res => {
console.log(3, res);
});
// 1 123
// 2 undefined
// 3 undefined
// -----
const promise = new Promise((resolve, reject) => {
resolve(123);
}).then(res => {
return new Promise((resolve, reject) => {
resolve(345)
})
}).then(res => {
console.log(res); // 345
})
复制代码
手写部分②——实现 then 方法
//...
class MyPromise{
//...
thenables = []; // 存放成功的回调函数
catchables = []; // 存放失败的回调函数
constructor(fn){
const resolve = value => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 当回调数组的长度大于0时,则循环数组,执行里面的每一个回调函数
this.thenables.length > 0 && this.thenables.forEach(handle => handle(value));
}
};
const reject = reason => {
if (this.status === PENDING) {
this.status = REJECTED;
this.value = reason;
this.catchables.length > 0 && this.catchables.forEach(handle => handle(reason));
}
};
// ...
}
// 如果当前的Promise已经是 fulfilled 或者是 rejected 状态了,那么就直接执行 onFulfilled 或者 onRejected
then(onFulfilled, onRejected) {
// 当没有传递处理的回调函数时,需要做一些处理
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
// 返回一个新的promise
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
// 用于捕获错误
try {
// 得到回调函数执行的结果,然后传入 ExecCb 函数
let x = onFulfilled(this.value);
this.ExecCb(x, promise2, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.value);
this.ExecCb(x, promise2, resolve, reject);
} catch (err) {
reject(err);
}
}, 0)
} else {
// 当前状态是pending时,需要把回调函数存放进数组中
this.thenables.push(() => {
try {
let x = onFulfilled(this.value);
this.ExecCb(x, promise2, resolve, reject);
} catch (err) {
reject(err);
}
});
this.catchables.push(() => {
try {
let x = onRejected(this.value);
this.ExecCb(x, promise2, resolve, reject);
} catch (err) {
reject(err);
}
});
}
});
return promise2;
}
ExecCb(x, promise, resolve, reject) {
// 当返回自己,那么就抛出错误信息
if (x === promise) {
return reject(new Error('Chaining cycle detected for promise #<Promise>'))
}
// 如果 x 是一个 promise对象的话,那么执行就执行then方法
if (x instanceof MyPromise) {
x.then(data => resolve(data), err => reject(err))
} else {
// 如果不是的话,则把值作为 resolve 的参数
resolve(x);
}
}
}
复制代码
测试:
// 模拟异步情况
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 3000)
}).then().then().then(res => console.log(res));
// 3秒钟之后输出 1
// ---
// 返回 Promise 的情况
const promise = new MyPromise((resolve, reject) => {
resolve(123);
}).then(res => {
return new MyPromise((resolve, reject) => {
resolve(345)
})
}).then(res => {
console.log(res); // 345
});
复制代码
到这,Promise
比较核心的功能我们都已经实现的差不多了,是不是对它更加的了解了呢?
完整代码:codesandbox.io/s/hopeful-w…
代码有些冗余,请谅解一下。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END