一、分析promise之前,先了解清楚EventLoop
事件循环机制从整体上告诉了我们 JavaScript 代码的执行顺序 Event Loop即事件循环。是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
先执行 Script 脚本,然后清空微任务队列,然后开始下一轮事件循环,继续先执行宏任务,再清空微任务队列,如此往复。
二、宏任务和微任务
因为js的一大特点是单线程,为了协调事件,交互渲染等等行为,防止主线程的阻塞,js有两种任务的执行模式:同步模式和异步模式。
异步任务下主要分为宏任务和微任务。ES6规范中
- 宏任务(Macrotask)包含:
- script(整体代码),
- setTimeout
- setInterval
- I/O,UI交互事件
- postMessage
- MessageChannel
- setImmediate(Node.js 环境)
- 微任务(Microtask)包含:
- Promise.then
- Object.observe
- MutationObserver
- process.nextTick(Node.js 环境)。
三、promise的基础实现
1、promise的基本功能
const promise = new Promise((resolve, reject) => {
resolve('success')
reject('err')
})
promise.then(res => {
console.log('resolve', res)
}, err => {
console.log('reject', err)
})
2、分析基本原理
- 一个Promise的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。
- 状态的改变只能是单向的,且变化后不可在改变。
- 一个promise对象接收的是一个callback,这个callback接收两个参数(resolve,reject),当我们在callback内执行resolve或reject的时候,就会调用Promise内定义的
resolve和reject函数,然后,resolve和reject函数会改变Promise的状态。
定义FsPromise,并定义参数:
function FsPromise (cb) {
//保存this值
var _this = this
//记录状态null为pending ,true为resolved, false为reject
var status = null
//记录resolve的参数
var param = null
//执行传入的callback并改变promise对象状态
cb(resolve,reject)
// resolve方法
function resolve(data) {}
//reject方法
function reject(err) {}
}
3、完善resolve和reject函数
但是如果promise的状态为pending,由于原始promise的状态是无法动态获取的,因此就需要在执行状态改变的时候同时执行onFulfilled和onRejected方法。
我们可以把这个方法放在原始promise对象的resolve和reject方法中执行。所以要在promise的对象定义中添加四个参数,分别记录onFulfilled和onRejected,以及then方法返回的新promise对象的resolve和reject。
然后如果执行then方法的时候promise对象的状态为pending的话,就将上述四个参数记录起来。
function FsPromise (cb) {
//保存this值
var _this = this
//记录状态null为pending ,true为resolved, false为reject
var status = null
//记录resolve的参数
var param = null
var nextResolve = null;
var nextReject = null;
// 记录then方法的参数,onFulfilled和onRejected
var asynconFulfilled = null;
var asynconRejected = null;
//执行传入的callback并改变promise对象状态
cb(resolve,reject)
// resolve方法
function resolve(data) {
//改变状态
status = true
param = data
nextResolve(asynconFulfilled(param))
}
//reject方法
function reject(err) {
status = false
param = err
nextReject(asynconRejected(param))
}
}
4、then的简单实现
- then方法接收两个可选的参数(onFulfilled, onRejected)
- then方法传进来的参数必须是函数
this.then = function(onFulfilled, onRejected){
// 返回一个新的promise对象
return new _this.constructor(function(resolve,reject){
// 判断异步代码是否执行完毕(是否resolve或reject)
// 若执行完毕就在then方法中立即执行,否则将四个参数记录下来,等待status就绪后再执行doAsyn*函数
// onFulfilled, onRejected这两个函数要在promise的状态变为pending或resolved的时候才能分别执行
if(status === true){
// param是promise对象完成后的结果
resolve(onFulfilled(param))
}else if(status === false){
reject(onRejected(param))
}else{
// 执行完毕
nextResolve = resolve;
nextReject = reject;
asynconFulfilled = onFulfilled;
asynconRejected = onRejected;
}
})
}
5、加入异步逻辑
// resolve方法
function resolve(data) {
status = true
param = data
// nextResolve(asynconFulfilled(param))
if(nextResolve){
doAsynconFulfilled(asynconFulfilled,nextResolve,nextReject);
}
}
//reject方法
function reject(err) {
status = false
param = err
// nextReject(asynconRejected(param))
if(nextReject){
doAsynconRejected(asynconRejected,nextResolve,nextReject);
}
}
// 主要核心代码
function doAsynconFulfilled(onFulfilled,resolve,reject){
setTimeout(function(){
// 判断onFulfilled是否为function
if(typeof onFulfilled === 'function'){
// 执行onFulfilled方法获取返回值promise()
let promise = onFulfilled(param);
// 如果promise为undefined 则执行 if内容
// 如果promise为MyPromise 对象 则执行 else if内容
// 如果promise为非MyPromise 对象 执行 else
if(promise === undefined){
resolve(param);
}else if(promise.constructor === _this.constructor){
// 等待传递进来的promise对象执行完毕,然后根据传递进来的promise对象的状态执行resolve或reject
Promise.then(function(param){
resolve(param);
},function(param){
reject(param);
})
}else{
// 执行then方法返回的对象的resolve
resolve(promise);
}
}else{
// 传递参数
resolve(param)
}
},0)
}
// 同理doAsynconFulfilled
function doAsynconRejected(onRejected,resolve,reject){
setTimeout(function(){
if(typeof onRejected === 'function'){
let promise = onRejected(param);
if(promise === undefined){
reject(param);
}else if(promise.constructor === _this.constructor){
Promise.then(function(param){
resolve(param);
},function(param){
reject(param);
})
}else{
reject(promise)
}
}else{
// 传递错误信息
reject(param);
}
},0)
}
将then方法中执行的resolve方法和reject方法换成异步方法:
- doAsynconFulfilled(onFulfilled, resolve, reject)
- doAsynconRejected(onRejected, resolve, reject)
6、使用上述代码,执行基本案例
const promise = new FsPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000);
})
promise.then(value => {
console.log('resolve', value)
}, reason => {
console.log('reject', reason)
})
// 执行结果为resolve success