(1)手摸手带你学promise规范

190 阅读6分钟

本文已参加[新人创作礼]活动,一起开启掘金创作之路。

前言:在本次分享中你将学习到什么

  1. promiseA+规范
  2. promise相关面试题
  3. 计算机以及浏览器原理
  4. 宏任务微任务

先来个思维导图

计算机原理

#进程和线程

概念:进程是CPU资源分配的最小单位,线程是CPU调度的最小单位。

拿以下例子来讲解,每一个小区下面有自己的居委会,有自己的居委仓库,他们负责各自的任务,只独立的动用自己的仓库,这就是线程干的事
而下面的“小人”就相当于居委的工作人员,他们就是线程,他们的特点就是共享,是服从每个工作调度的最小单位

区别:进程是有自己独立资源的;而线程是没有自己仓库的,线程之间的资源是共享的

面试题:

1.浏览器 chrome新开一个窗口,tab页算是进程还是线程?

答案;进程。从概念出发去理解这个问题,因为进程是由独立的资源的,他们互不影响,回想日常操作,A页面死循环了的话,B页面也可以正常执行。

发散面试题

2.窗口(进程间)通信问题,面试官会问,那你的浏览器的窗口之间是怎么进行通信的

答案:本质是在问你浏览器的存储问题 -- storage、cookie=>多种存储之间的区别

3.浏览器的原理,(既然你刚刚提到浏览器,那你讲讲浏览器的原理巴拉巴拉)

答案:如下

浏览器原理

推荐一篇大佬文章《从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理》

浏览器的内核(核心线程)

JS执行原理(高级工程师必问)(暂不熟悉待定)

值得一提的是,我们从刚刚一直往下的知识点,是从宏观到微观的

面试题

  1. JS堆栈的执行顺序与堆栈溢出 => 涉及问题:性能优化

宏任务微任务

概念:js任务分为宏任务和微任务.宏任务主要包括:scrip(JS 整体代码)、setTimeout、setInterval、setImmediate、I/O、UI 交互 微任务主要包括:Promise(重点关注)、process.nextTick(Node.js)、MutaionObserver

纵向我们来看的话,任务又分为同步和异步,区分与上面的宏微任务,我们大致就把任务分为了两个方向. 先区分同步异步,再区分宏微任务

需要记住的是:

  1. 宏任务的优先级是大于微任务的,在宏任务里面进行判断是否有可执行的微任务,有的话就执行微任务,没有的话就执行下一个宏任务,即**"有微则微,无微则宏"**

面试题

js执行顺序题

问一下代码的打印顺序
答案: hi promise time out

    setTimeout(() => {            console.log('time out');        },1000 );        Promise.resolve(1).then(() =>{            console.log('promise');        })        console.log('hi');

思路: 

首先第一步肯定是先执行同步的,所以第一个打印为hi 没什么争议

而setTimeout 是宏任务会先被执行,但是里面的代码会进入到到event queue等待,所以Promise.resolve进入主线程,然后被执行完,才会去执行我们的even queue(事件队列,由于他先进来,反而被塞到最后面,就想吃薯片一样,最先放进去的,反而最晚吃到)

promise

讲回今天的主体,promise

概念:promise的出现,是为了解决回调地狱(关键在于callback)问题,拯救了回调导致的无穷嵌套.

   //回调地狱写法,嵌套过深
 // 1. 写一个异步定时
    setTimeout(() => {
        console.log('Time out')
    }, 2000)
    // 2. 写一个异步请求
    request.onreadystatechange = () => {
        if(request.readyState === 4) {
            const _status = request.statue
            if (_status === 200) {
                const _res = request.responseText
                return success(_res)
            } else {
                return fail(_status)
            }
        }
    }
    // 3. 延时后再请求
    setTimeout(() => {
        console.log('Time out')
        request.onreadystatechange = () => {
            if(request.readyState === 4) {
                const _status = request.statue
                if (_status === 200) {
                    const _res = request.responseText
                    return success(_res)
                } else {
                    return fail(_status)
                }
            }
        }
    }, 2000)
    // 4. 再延时再请求?- 回调地狱
    setTimeout(() => {
        console.log('Time out')
        request.onreadystatechange = () => {
            if(request.readyState === 4) {
                const _status = request.statue
                if (_status === 200) {
                    const _res = request.responseText
                    setTimeout(() => {
                        console.log('Time out')
                        request.onreadystatechange = () => {
                            if(request.readyState === 4) {
                                const _status = request.statue
                                if (_status === 200) {
                                    const _res = request.responseText
                                    return success(_res)
                                } else {
                                    return fail(_status)
                                }
                            }
                        }
                    }, 2000)
                    return success(_res)
                } else {
                    return fail(_status)
                }
            }
        }
    }, 2000)

利用promise解决回调地狱

    // 5. promise的出现,拯救了回调导致的无穷嵌套
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('OK')
        }, 1000)
    }).then(r => {
        console.log('then: ' + r)
    }).catch(err => {
        console.log('catch: ' + err)
    })

    // 6. 多个异步顺序执行 => 链式调用
    function wait500(input) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(input + 500)
            }, 500)
        })
    }
    function wait1000(input) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(input + 1000)
            }, 1000)
        })
    }
    const p = new Promise((resolve, reject) => {
        resolve(1)
    })
    p.then(wait500)
    .then(wait1000)
    .then(wait500)
    .then(wait1000)
    .then(result => {
        console.log('end' + result)
    })
//promise应该具备有批量处理的能力
    // 7.全部执行完成后再操作
    Promise.all([wait500, wait1000]).then(result => {
        console.log('all end', result) // [f,f,f,f]
    })

    // 8. 一旦有执行完成的,立刻操作
    Promise.race([wait500, wait1000]).then(result => {
        console.log('race end', result) // f
    })
//面试题:all 和race返回值问题

利用promiseA+规范按着思路写一遍

  1. promise有哪些状态?对应的值有哪些? -- pending fulfilled rejected
  2. new Promise 的时候我们的执行器executor(),执行参数是什么? -- resolve reject
  3. promise的默认状态是什么?状态的流转是怎样的? -- 默认状态pending ,状态流转 p=>f, p=>r
  4. promise value保存成功状态的枚举? undefined/thenable/ promise
  5. 失败状态值? -- reason保存失败
  6. promise一定有then ,then接收来源> -- 两个回调 成功的话onFulfilled 返回value, 失败的话onRejected,返回reason
  • 两个回调onFulfilled(value) + onRejected(reason)

    // 三个状态:PENDING FULFILLED REJECTED
    const PENDING = 'PENDING'
    const FULFILLED = 'FULFILLED'
    const REJECTED = 'REJECTED'
    
    class Promise { // 类
        constructor(executor) { // 构造
            // 默认状态的处理: PENDING
            this.status = PENDING
    
            // 成功状态的值
            this.value = undefined
            // 失败状态的值
            this.reason = undefined
    
            // 成功状态的回调
            let resolve = value => {
                if (this.status === PENDING) {
                    this.status = FULFILLED
                    this.value = value
                }
            }
    
            // 失败状态的回调
            let reject = reason => {
                if (this.status === PENDING) {
                    this.status = REJECTED
                    this.reason = reason
                }
            }
            
            try {
                executor(resolve, reject)
            } catch (error) {
                reject(error)
            }
        }
    
        then(onFulfilled, onRejected) {
            if (this.status === FULFILLED) {
                onFulfilled(this.value)
            }
    
            if (this.status === REJECTED) {
                onRejected(this.reason)
            }
        }
    }
    
    const promise = new Promise((resolve, reject) => {
        resolve('成功')
    }).then(data => {})
    .catch(err => {})
    
    // 异步
    // 区别 - 依次调用
    class Promise { // 类
        constructor(executor) { // 构造
            // 默认状态的处理: PENDING
            this.status = PENDING
    
            // 成功状态的值
            this.value = undefined
            // 失败状态的值
            this.reason = undefined
    
            // 存放成功的回调
            this.onResolvedCallbacks = []
            // 存放失败的回调
            this.onRejectedCallbacks = []
    
            // 成功状态的回调
            let resolve = value => {
                if (this.status === PENDING) {
                    this.status = FULFILLED
                    this.value = value
    
                    // 依次调用对应函数的执行
                    (this.onResolvedCallbacks || []).forEach(fn => fn())
                }
            }
    
            // 失败状态的回调
            let reject = reason => {
                if (this.status === PENDING) {
                    this.status = REJECTED
                    this.reason = reason
    
                    // 依次调用对应函数的执行
                    (this.onRejectedCallbacks || []).forEach(fn => fn())
                }
            }
    
            try {
                executor(resolve, reject)
            } catch (error) {
                reject(error)
            }
        }
    
        then(onFulfilled, onRejected) {
            if (this.status === FULFILLED) {
                onFulfilled(this.value)
            }
    
            if (this.status === REJECTED) {
                onRejected(this.reason)
            }
    
            if (this.status === PENDING) {
                this.onResolvedCallbacks.push(() => {
                    onFulfilled(this.value)
                })
                this.onRejectedCallbacks.push(() => {
                    onRejected(this.reason)
                })
            }
        }
    }
    
    // 启示:同步 => 异步
    // 顺序和空间的关系