本文已参加[新人创作礼]活动,一起开启掘金创作之路。
前言:在本次分享中你将学习到什么
- promiseA+规范
- promise相关面试题
- 计算机以及浏览器原理
- 宏任务微任务
先来个思维导图
计算机原理
#进程和线程
概念:进程是CPU资源分配的最小单位,线程是CPU调度的最小单位。
拿以下例子来讲解,每一个小区下面有自己的居委会,有自己的居委仓库,他们负责各自的任务,只独立的动用自己的仓库,这就是线程干的事
而下面的“小人”就相当于居委的工作人员,他们就是线程,他们的特点就是共享,是服从每个工作调度的最小单位
区别:进程是有自己独立资源的;而线程是没有自己仓库的,线程之间的资源是共享的
面试题:
1.浏览器 chrome新开一个窗口,tab页算是进程还是线程?
答案;进程。从概念出发去理解这个问题,因为进程是由独立的资源的,他们互不影响,回想日常操作,A页面死循环了的话,B页面也可以正常执行。
发散面试题
2.窗口(进程间)通信问题,面试官会问,那你的浏览器的窗口之间是怎么进行通信的
答案:本质是在问你浏览器的存储问题 -- storage、cookie=>多种存储之间的区别
3.浏览器的原理,(既然你刚刚提到浏览器,那你讲讲浏览器的原理巴拉巴拉)
答案:如下
浏览器原理
推荐一篇大佬文章《从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理》
浏览器的内核(核心线程)
JS执行原理(高级工程师必问)(暂不熟悉待定)
值得一提的是,我们从刚刚一直往下的知识点,是从宏观到微观的
面试题
-
JS堆栈的执行顺序与堆栈溢出 => 涉及问题:性能优化
宏任务微任务
概念:js任务分为宏任务和微任务.宏任务主要包括:scrip(JS 整体代码)、setTimeout、setInterval、setImmediate、I/O、UI 交互 微任务主要包括:Promise(重点关注)、process.nextTick(Node.js)、MutaionObserver
纵向我们来看的话,任务又分为同步和异步,区分与上面的宏微任务,我们大致就把任务分为了两个方向. 先区分同步异步,再区分宏微任务
需要记住的是:
- 宏任务的优先级是大于微任务的,在宏任务里面进行判断是否有可执行的微任务,有的话就执行微任务,没有的话就执行下一个宏任务,即**"有微则微,无微则宏"**
面试题
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+规范按着思路写一遍
- promise有哪些状态?对应的值有哪些? -- pending fulfilled rejected
- new Promise 的时候我们的执行器executor(),执行参数是什么? -- resolve reject
- promise的默认状态是什么?状态的流转是怎样的? -- 默认状态pending ,状态流转 p=>f, p=>r
- promise value保存成功状态的枚举? undefined/thenable/ promise
- 失败状态值? -- reason保存失败
- 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) }) } } } // 启示:同步 => 异步 // 顺序和空间的关系