前端的路程三之事件循环&Promise

事件循环(eventloop)

前端事件循环指的是js执行的机制,概括一下:
javascript代码都可以当作任务,其中划分宏任务和微任务,在执行栈中每次处理完宏任务都会去清空一下微任务的队列。
宏任务
setTimeout、setInterval、I/O 操作、DOM 事件等;
微任务
Promise.then ES6、、Object.observer、MutationObserver、process.nextTick、queueMicrotask创建的微任务等;
整体来讲js在从上往下执行的时候遇到的微任务会被放在微任务队列,当前宏任务执行完毕之后就会将微任务推入执行栈执行,又可能会产生新的宏微任务,当然每次微任务被清空时说明本次事件循环结束
图例:浏览器的任务执行流程
请添加图片描述

Promise

Promise是ES6新增特性,用于解决异步回调或者说回调地狱。
promise有三种状态pendding、rejected、resolved,一个 promise 对象状态只能改变一次。
优点:

  1. 解决回调链
  2. 可链式调用
  3. 有all、race、any等api便于异步任务资源整合

缺点:

  1. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部;
  2. 当前pendding状态无法知道进展;
  3. 无法取消;

简单实现promise(面试重点)

整理promise的要点
  1. promise接收一个函数,函数中有两个参数resolve和reject函数,所以需要定义resolve、reject函数并且接收对应的参数;
  2. promise有三个状态pendding、rejected、fulfalled,默认pendding状态,可通过resolve和reject函数改变状态;
  3. then函数
    函数接收两个参数一个是成功的回调一个是失败的回调,必须是函数,状态变为fulfalled/rejected的时候去调用对应的函数
function PromiseF (callback){
    this.status = 'pendding'
    this.value = null //储存resolve传递的值
    this.reason = null //储存reject传递的值
    const resolve = (value)=>{
            if(this.status == 'pendding'){
                this.value = value
                this.status = 'fulfalled'
            }
    }
    const reject = (reason)=>{
            if(this.status == 'pendding'){
                this.reason = reason
                this.status = 'rejected'
            }
    }
    callback(resolve,reject)
}

PromiseF.prototype.then = function (onResolved,onRejected){
    onResolved =  typeof onResolved == 'function'?onResolved :(data)=>data
    onRejected =  typeof onRejected == 'function'?onRejected :(err)=>{throw err}
    if(this.status == 'fulfalled'){
        onResolved(this.value)
    }
    if(this.status == 'rejected'){
       	onResolved(this.reason)
    }
}

简单实现promise但是还无法链式调用无法支持异步

promise进阶 实现支持异步和链式回调
  1. 支持异步需要resolve / reject 执行了之后,再执行 onfulfilled 和 onrejected;
  2. onfulfilled 和 onjected 应该是微任务;
  3. 链式回调的实现说明调用then函数之后的返回值也是一个promise,或者说函数的返回值应该是promise的一个新的resolve;
    那么利用创建微任务(queueMicrotask)的api去执行对应的函数,创建onFulfalledArr、onRejectedArr去收集对应的函数回调,然后循环数组去执行函数
function PromiseF (callback){
    this.status = 'pendding'
    this.value = null //储存resolve传递的值
    this.reason = null //储存reject传递的值
    this.onFulfalledArr = []
    this.onRejectedArr = []
    const resolve = (value)=>{
        queueMicrotask(()=>{
            console.log('微任务resolve')
            if(this.status == 'pendding'){
                this.value = value
                this.status = 'fulfalled'
                this.onFulfalledArr.forEach(fn=>{
                    fn(value)
                })
            }
        })
    }
    const reject = (reason)=>{
        queueMicrotask(()=>{
        	console.log('微任务reject')
            if(this.status == 'pendding'){
                this.reason = reason
                this.status = 'rejected'
                this.onRejectedArr.forEach(fn=>{
                    fn(reason)
                })
            }
        })
    }
    callback(resolve,reject)
}

PromiseF.prototype.then = function (onResolved,onRejected){
    onResolved =  typeof onResolved == 'function'?onResolved :(data)=>data
    onRejected =  typeof onRejected == 'function'?onRejected :(err)=>{throw err}
    let promiseBack;
    if(this.status == 'fulfalled'){
        return promiseBack = new PromiseF((resolve,reject)=>{
            queueMicrotask(() => {
                console.log('微任务.then直接执行')
                try {
                    const result = onResolved(this.value)
                    resolve(result)
                } catch (error) {
                    reject(error)
                }
            })
        })
    }
    if(this.status == 'rejected'){
        return promiseBack = new PromiseF((resolve,reject)=>{
            queueMicrotask(() => {
            	console.log('微任务.then直接执行')
                try {
                    const reason = onResolved(this.reason)
                    reject(reason)
                } catch (error) {
                    reject(error)
                }
            })
        })
    }
    if(this.status == 'pendding'){
        return promiseBack = new PromiseF((resolve,reject)=>{
            console.log('微任务.then收集依赖')
            try {
                this.onFulfalledArr.push(()=>{
                    const result = onResolved(this.value)
                    resolve(result)
                })
            } catch (error) {
                reject(error)
            }
            try {
                this.onRejectedArr.push(()=>{
                    const reason = onRejected(this.reason)
                    reject(reason)
                })
            } catch (error) {
                reject(error)
            }
        })
    }
}
promise的另一个重点链式调用的resolvePromise 规范

这里是直接去拿的文档,知道有这么回事儿就好,面试一般不会深追这里,逻辑太复杂了

  • 如果 promise2 和 x 相等,那么 reject error;
  • 如果 promise2 是一个 promise
    • 如果 x 是一个pending 状态,那么 promise2 必须要再 pending, 直到 x 变成 fulfilled / rejected
    • 如果 x 被 fulfilled, fulfill promise with the same value
    • 如果 x 被 rejected, reject promise with the same reason
  • 如果 x 是一个 object 或者 function
    • Let thenable = x.then
    • 如果 x.then 这一步出错,那么 reject promise with e as the reason
    • 如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromiseFn)
      • resolvePromiseFn 的入参是y, 执行 resolvePromise(promise2, y, resolve, reject)
      • rejectPromiseFn 的入参是 r, reject promise with r
      • 如果 resolvePromiseFn 和 rejectPromiseFn 都调用了,那么第一个调用优先,后面的忽略
      • 如果调用then 抛出异常
        • 如果 resolvePromise 或 rejectPromise 已经被调用,可以忽略
      • 如果 then 不是一个 function, fulfill promise with x
  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值