Promise用法

Promise是ES6中新的异步语法,解决了回调地域的问题
new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(1);
}, 2000);
}).then(val => {
console.log('val',val);
return new Promise(resolve => {
setTimeout(()=>{
resolve(2);
}, 2000)
})
}).then(val => {
console.log('val',val);
})
// 1
// 2
实现状态切换
- Promise实例有三个状态,pending, fulfilled, rejected
- Promise实例在构造是可以传入执行函数,执行函数有两个形参resolve, reject可以改变Promise状态,Promise的状态一旦改变后不可再进行改变
- 执行函数会再创建Promise实例时,同步执行
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class Promise2 {
constructor (executor) {
this.status = 'pending';
this.value = null;
this.reason = null;
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
}
}
executor(resolve, reject);
}
}
let p = new Promise2((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
实现then异步执行
Promise实例可以调用then方法并且传入回调:
如果调用then时,Promise实例是fulfilled状态,则马上异步执行传入的回调。
如果调用then时,Promise是pending状态,传入的回调会等到resolve后再异步执行
例子1 Promise是ffulfilled状态
let p = new Promise((resolve, reject) => {
console.log(1);
resolve(2);
console.log(3);
})
p.then(val => {
console.log(val);
})
// 执行顺序为 1 3 2、因为resolve之后是异步执行
例子2 Promise是pending状态
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
})
})
p.then(val => {
console.log(val);
})
// 运行一秒后才会打印 1 因为需要等resolve执行完之后再打印
实现then异步执行思路: 需要用回调先保存到队列中,在resolve后异步执行队列里的回调,在then时判断实例的状态再决定是将回调推入队列,还是直接异步执行回调。
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class Promise2 {
constructor (executor) {
this.status = 'pending';
this.value = null;
this.reason = null;
this.onFulfilledCallbacks = []; // 成功的回调队列
this.onRejectedcallbacks = []; // 失败的回调队列
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 异步执行队列中的回调
setTimeout(() => {
console.log('onFulfilledCallbacks',this.onFulfilledCallbacks);
this.onFulfilledCallbacks.forEach(callbacks => {
callbacks(this.value);
})
})
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 异步执行队列中的回调
setTimeout(() => {
this.onRejectedcallbacks.forEach(callbacks => {
callbacks(this.reason);
})
})
}
}
executor(resolve, reject);
}
then (onFulfilled, onRejected) {
// 状态是已完成的
if (this.status === FULFILLED) {
setTimeout(()=>{
onFulfilled(this.value);
})
}
// 状态是失败的
if (this.staus === REJECTED) {
setTimeout(() => {
onRejected(this.reason);
})
}
// 状态pending中
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled); // 存储回调函数
this.onRejectedcallbacks.push(onRejected); // 存储回调函数
}
}
}
let p = new Promise2((resolve, reject) => {
console.log(1);
resolve(2);
console.log(3);
})
p.then(val => {
console.log(val);
})
//打印 1 3 2
let p = new Promise2((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(2);
})
})
p.then(val => {
console.log(val);
})
// 打印 2 1
resolve Promise实例的情况
resolve的值有可能也是个Promise实例,这时候就要用前述实例自己resolve的值
let p = new Promise((resolve, reject) => {
const p2 = new Promise((resolve2, reject2) => setTimeout(() => resolve2(1), 2000));
resolve(p2);
})
p.then(value => {
console.log('val',value);
// 两秒钟后输出 2
})
因此需要再Promise1的resolve函数中进行判断,是Promise实例则在这个Promise实例(Promise2)后接一个then,并且将Promise1的resolve作为回调传入Promise2的then
const resolve = (value) => {
// 判断value如果是否是Promise实例
if (value instanceof this.constructor) {
// Promise2解决后,将外层的Promise也解决
value.then(resolve, reject)
return;
}
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 异步执行队列中的回调
setTimeout(() => {
this.onFulfilledCallbacks.forEach(callbacks => {
callbacks(this.value);
})
})
}
}
let p = new Promise2((resolve, reject) => {
const p2 = new Promise2((resolve2, reject2) => setTimeout(() => resolve2(1), 2000));
resolve(p2);
})
p.then(value => {
console.log('val',value);
// 两秒钟后输出 2
})
实现链式调用
then可以链式调用,而且前一个then的回调的返回值,如果不是Promise实例,则下一个then回调的传参值就是上一个then回调的返回值,如果Promise实例,则下一个then回调的传参值,是上一个then回调返回的Promise实例的解决值(value)
let p = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 2000)
})
p.then(val => {
// 如果Promise实例,则下一个then回调的传参值,是上一个then回调返回的Promise实例的解决值(value)
console.log('val', val);
return new Promise(resolve => setTimeout(() => resolve(2), 2000));
}).then(val => {
// 如果不是Promise实例,则下一个then回调的传参值就是上一个then回调的返回值
console.log('val',val);
return 3
}).then(val => {
console.log('val',val);
})
// 打印结果是两秒后打印1 再两秒后2和3一起打印-
既然能够链式调用,那么then方法本身的返回值必定是一个Promise实例,那么返回的Promise实例是不是自身呢?答案显而易见:不是。如果一个Promise的then方法的返回值是Promise自身,在new一个Promise时,调用了resolve方法,因为Promise的状态一旦更改便不能再次更改,那么下面的所有的then便只能执行成功的回调,无法进行错误处理,这显然不符合Promise的规范和设计Promise的初衷。
因此then方法会返回一个新的Promise实例
then (onFulfilled, onRejected) {
return new this.constructor((resolve, reject) => {
// 状态是已完成的
if (this.status === FULFILLED) {
setTimeout(()=>{
// 如果语法有错误也要reject出去
try {
let callbakcValue = onFulfilled(this.value);
resolve(callbakcValue);
}catch (e) {
reject(e);
}
})
}
// 状态是失败的
if (this.staus === REJECTED) {
setTimeout(() => {
try {
let callBackValue = onRejected(this.reason);
resolve(callBackValue);
}catch (e) {
reject(e);
}
})
}
// 状态pending中
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(() => {
try {
let callBackValue = onFulfilled(this.value);
resolve(callBackValue);
}catch (e) {
reject(e)
}
}); // 存储回调函数
this.onRejectedcallbacks.push(() => {
try {
let callBackValue = onRejected(this.reason);
resolve(callBackValue);
}catch (e) {
reject(e)
}
}); // 存储回调函数
}
});
}
let p = new Promise2((resolve, reject) => {
setTimeout(() => resolve(1), 2000)
})
p.then(val => {
// 如果Promise实例,则下一个then回调的传参值,是上一个then回调返回的Promise实例的解决值(value)
console.log('val', val);
return new Promise2(resolve => setTimeout(() => resolve(2), 2000));
}).then(val => {
// 如果不是Promise实例,则下一个then回调的传参值就是上一个then回调的返回值
console.log('val',val);
return 3
}).then(val => {
console.log('val',val);
})
// 打印结果是两秒后打印1 再两秒后2和3一起打印
实现catch-resolve-reject
calss Promise2 {
static resolve (value) {
// resolve中如果形参是个Promise,直接返回
if (value instanceof this) {
return value;
}
return new this((reslove, reject) => {
reslove(value);
})
}
static reject (reason) {
// reject不用返回
return new this((reslove, reject) => {
reject(reason);
})
}
constructor (executor) {...},
then (onFulfilled, onRejected) {...},
catch (onRejected) {
return this.then(null, onRejected)
}
}
// catch 方法
let p = new Promise2((resolve, reject) => {
reject(1);
})
p.catch(e => {
console.log('e', e);
})
// Promise.resolve的静态方法
let p = Promise2.resolve(1);
// Promise.reject的静态方法
let p = Promise2.reject(1)
实现all
calss Promise2 {
static resolve (value) {...}
static reject (reason) {...}
static all (promises) {
return new this((resolve, reject) => {
let promiseNum = promises.length;
let resolvedNum = 0;
let resolvedValues = [...promises];
for (let i = 0; i < promiseNum; i++) {
this.resolve(promises[i])
.then(val => {
resolvedNum++;
resolvedValues[i] = val;
if (resolvedNum === promiseNum) {
// 所有的promise都已经解决
resolve(resolvedValues);
}
},
reason => {
reject(reason);
});
}
});
}
constructor (executor) {...},
then (onFulfilled, onRejected) {...},
catch (onRejected) {...}
}
let p = Promise2.all([
new Promise2((resolve, reject) => setTimeout(() => resolve(1), 1000)),
new Promise2((resolve, reject) => setTimeout(() => resolve(2), 2000)),
new Promise2((resolve, reject) => setTimeout(() => resolve(3), 3000)),
]);
p.then(val => {
console.log('val', val);
});
// 6秒后打印 1 2 3
实现race
calss Promise2 {
static resolve (value) {...}
static reject (reason) {...}
static all (promises) {...}
static race (promises) {
return new this((resolve, reject) => {
let length = promises.length;
for (let i = 0; i < length; i++) {
this.resolve(promises[i])
.then(
val => {
resolve(val);
},
reason => {
reject(reason);
}
);
}
});
}
constructor (executor) {...},
then (onFulfilled, onRejected) {...},
catch (onRejected) {...}
}
let p = Promise2.race([
new Promise2((resolve, reject) => setTimeout(() => resolve(1), 1000)),
new Promise2((resolve, reject) => setTimeout(() => resolve(2), 2000)),
new Promise2((resolve, reject) => setTimeout(() => resolve(3), 3000)),
]);
p.then(val => {
console.log('val', val);
});
// 打印最快的返回结果 1
宏任务与微任务
macroTask(宏任务)是指将任务排到下一个事件循环
microTask(微任务)是指将任务排到当前事件循环的队尾,执行时机会比宏任务更早。
Promise的标准里没有规定Promise里的异步该使用哪种,但在node和浏览器的实现里都是使用的microTask(微任务)。
js是单线程所有主线程的同步任务先执行,然后执行微任务队列的程序,最后执行宏任务队列,秉承先进先出的原则。
宏任务Api包括: setTimeout(),setInterval(),setImmediate(nodeApi),requestAnimationFrame(),各种IO操作,网络请求。
微任务Api包括:process.nextTick(nodeApi),MutationObserver()。Promise.then catch finally
使用微任务替换上述中Promise中的setTimeout宏任务
// 微任务方法
let nextTick = (function () {
let callbacks = [];
let counter = 1;
let node = document.createElement('div');
function handler () {
let copy = callbacks.slice();
callbacks = [];
copy.forEach(cb => cb());
}
let obServer = new MutationObserver(handler);
obServer.observe(node, {
childList: true,
});
return function (cb) {
callbacks.push(cb);
// 触发MutationObserver
counter = (counter + 1) % 2;
node.innerHTML = counter;
};
})();
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class Promise2 {
// Promise.resolve方法
static resolve (value) {
// resolve中如果形参是个Promise,直接返回
if (value instanceof this) {
return value;
}
return new this((reslove, reject) => {
reslove(value);
});
}
// Promise.reject方法
static reject (reason) {
// reject不用返回
return new this((reslove, reject) => {
reject(reason);
});
}
// Promise.all方法
static all (promises) {
return new this((resolve, reject) => {
let promiseNum = promises.length;
let resolvedNum = 0;
let resolvedValues = [...promises];
for (let i = 0; i < promiseNum; i++) {
this.resolve(promises[i])
.then(val => {
resolvedNum++;
resolvedValues[i] = val;
if (resolvedNum === promiseNum) {
// 所有的promise都已经解决
resolve(resolvedValues);
}
},
reason => {
reject(reason);
});
}
});
}
// Promise.race方法
static race (promises) {
return new this((resolve, reject) => {
let length = promises.length;
for (let i = 0; i < length; i++) {
this.resolve(promises[i])
.then(
val => {
resolve(val);
},
reason => {
reject(reason);
}
);
}
});
}
constructor (executor) {
this.status = 'pending';
this.value = null;
this.reason = null;
this.onFulfilledCallbacks = []; // 成功的回调队列
this.onRejectedcallbacks = []; // 失败的回调队列
const resolve = (value) => {
// 判断value如果是否是Promise实例
if (value instanceof this.constructor) {
// Promise2解决后,将外层的Promise也解决
value.then(resolve, reject);
return;
}
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 异步执行队列中的回调
nextTick(() => {
this.onFulfilledCallbacks.forEach(callbacks => {
callbacks(this.value);
});
});
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 异步执行队列中的回调
nextTick(() => {
this.onRejectedcallbacks.forEach(callbacks => {
callbacks(this.reason);
});
});
}
};
executor(resolve, reject);
}
then (onFulfilled, onRejected) {
return new this.constructor((resolve, reject) => {
// 状态是已完成的
if (this.status === FULFILLED) {
nextTick(() => {
// 如果语法有错误也要reject出去
try {
let callbakcValue = onFulfilled(this.value);
resolve(callbakcValue);
} catch (e) {
reject(e);
}
});
}
// 状态是失败的
if (this.status === REJECTED) {
nextTick(() => {
try {
let callBackValue = onRejected(this.reason);
resolve(callBackValue);
} catch (e) {
reject(e);
}
});
}
// 状态pending中
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(() => {
try {
let callBackValue = onFulfilled(this.value);
resolve(callBackValue);
} catch (e) {
reject(e);
}
}); // 存储回调函数
this.onRejectedcallbacks.push(() => {
try {
let callBackValue = onRejected(this.reason);
resolve(callBackValue);
} catch (e) {
reject(e);
}
}); // 存储回调函数
}
});
}
catch (onRejected) {
return this.then(null, onRejected);
}
}
因为Promise本身使用的是微任务,所以我们需要把上述实现代码中的宏任务steTimeout替换成实现的微任务方法。这样会打印了1后再等待1秒,打印2后同时打印3,使用宏任务会打印2后,依次打印3,会有执行间隔。
网上的资料深浅不一,本人也是处在学习的过程中的总结,如果发现错误,欢迎留言指出~