Promise的使用和特点
- Promise是一个构造函数,接收一个函数(executor)作为参数,这个函数的参数有两个,resolve,reject
- executor是立即执行函数,也就是在new Promise的时候,在Promise构造函数中直接被调用的
- resolve, 是内部创建的函数,用户调用该函数可以让promise变成成功态(fufilled)
- reject,是内部创建的函数,用户调用该函数可以让promise变成失败态(rejected)
- promise有三种状态,默认是padding(等待态)、成功态(fufilled)、失败态(rejected)
- 状态不可逆,一旦成功就不能失败,一旦失败就不能成功
- 常用的then方法
- 是原型方法
- then方法调用接收两个参数作为参数,1. onFulfilled / 2. onRejected
- then方法支持链式调用,可以一直.then().then()....
- then方法的两个参数onFulfilled和onRejected的返回值,会作为下一次then的结果,如果返回值是一个promise,会解析这个promise,将promise的结果作为下一次then的结果
// 1. 创建promise实例
const p = new Promise((resolve, reject) => {
// 直接执行的逻辑...
})
p.then(res => {
return 100
return new Promise((resolve, reject) => { resolve('hello') })
}).then(res => {
console.log(res) // 100 / 'hello'
})
Promise A+ 规范,实现符合规范的promise
实现流程:
- Promise是一个构造函数,参数是一个executor函数
- executor的参数是resove和reject
- promise的三个状态,状态不可逆
- promise的两个值:1. 成功的value 2. 失败的原因reason
- executor中逻辑异步的处理,使用发布订阅的模式处理异步
- then方法中两个参数onFulfilled和onRejected的返回值的处理,使用resolvePromise来递归解析promise
实现代码:
class Promise {
constructor(executor) {
// promise 的三个状态 padding fulfilled rejected
this.value = null;
this.reason = null;
this.fulfilledCbs = []; // 成功回调
this.rejectedCbs = [];
this.status = 'padding'
const resolve = (value) => {
if (this.status === 'padding') {
this.status = 'fulfilled';
this.value = value
for (let i = 0; i < this.fulfilledCbs.length; i++) {
const fn = this.fulfilledCbs[i];
fn()
}
}
}
const reject = (reason) => {
if (this.status === 'padding') {
this.status = 'rejected'
this.reason = reason
for (let i = 0; i < this.rejectedCbs.length; i++) {
const fn = this.rejectedCbs[i];
fn()
}
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
// then 方法返回一个新的promise,叫promsie2
// then 方法中的回调函数返回值可以是普通值或者promsie,如果是promise,会解析promise的值作为下一次then的值
then(onFulfilled, onRejected) {
const isFunction = val => typeof val === 'function';
onFulfilled = isFunction(onFulfilled) ? onFulfilled : (value) => value; // 将then的结果透传给下一次then
onRejected = isFunction(onRejected) ? onRejected : (error) => {
throw error
}
let promise2; // then方法返回的promise叫promise2
if (this.status === 'padding') { // 说明executor中的逻辑是异步执行的
promise2 = new Promise((resolve, reject) => {
this.fulfilledCbs.push(() => {
setTimeout(() => {
try {
// then方法回调的返回值叫做x
const x = onFulfilled(this.value)
resovlePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
this.rejectedCbs.push(() => {
setTimeout(() => {
try {
// then方法回调的返回值叫做x
const x = onRejected(this.reason)
resovlePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
})
} else if (this.status === 'fulfilled') {
promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// then方法回调的返回值叫做x
const x = onFulfilled(this.value)
resovlePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
} else if (this.status === 'rejected') {
promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// then方法回调的返回值叫做x
const x = onRejected(this.reason)
resovlePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
}
return promise2;
}
}
function resovlePromise(promise2, x, resolve, reject) {
// 返回的x可能是一个promise,但是一定不能和promise2相同
if (promise2 === x) {
return reject(new TypeError("same promise"));
}
// 分析x的值,可能是一个普通的值,可能是一个promise
// 1. 如果 x 是一个 promise,使用它的状态
if (x instanceof Promise) {
x.then(val => {
// y有可能也是一个promise,递归解析
resovlePromise(promise2, val, resolve, reject)
}, reject)
}
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
let flag = false;
if (typeof then === 'function') {
try {
// x 作为this调用then
then.call(x, y => {
if (!flag) {
resovlePromise(promise2, y, resolve, reject)
flag = true;
}
}, r => {
if (!flag) {
reject(r)
flag = true;
}
})
} catch (e) {
if (!flag) {
reject(e)
flag = true;
}
}
} else {
resolve(x)
}
} catch (e) {
reject(e)
}
} else {
resolve(x)
}
}
测试promise
- 增加测试代码
Promise.deferred = function () {
let def = {};
def.promise = new Promise(function (resolve, reject) {
def.resolve = resolve;
def.reject = reject;
});
return def;
}
module.exports = Promise
- 安装测试包
npm install -g promises-aplus-tests
promises-aplus-tests promise.js