Promise解析
- 什么是异步
//异步执行
let count = 1
let timer = setTimeout(() => {
count++
console.log('in', count)
}, 1000)
console.log('out', count)
// 循环执行+终止
let count = 1
let timer = setInterval(() => {
count++
console.log('in', count)
}, 1000)
console.log('out', count)
setTimeout(() => {
clearInterval(timer)
}, 5000);
1.进程和线程
a.概念与区别
如上图所示,认为每个小区是一个单独的进程,cpu分配给每个小区居委资源,所以每个进程单独占有自己的资源,认为小区居委的不同工作人员是不同的线程,这些工作人员即线程占有当前小区即进程的共同资源,即线程间可以共享cpu资源。
进程是cpu资源分配的最小单位,线程是cpu调度的最小单位
b. 面试题:
- 映射到前端: 浏览器。chrome新开的一个窗口,tab页是进程还是线程?
答案:进程。 从概念上考虑,进程和线程的区别是进程拥有独立的资源,进程不会共享资源,而线程是共享所属进程的资源的,显然,两个tab之间并不共享资源,两个tab各自是独立的window,属于独立的两个进程。譬如,a页面陷入死循环,但b页面不会受到影响,因为他们并不在一个进程内。 - 发散:
方向一: 窗口(进程间)通信?浏览器的存储 - storage、cookie => 多种存储的区别
方向二: 浏览器原理
浏览器在一个进程中有多个线程,即各种引擎。
- GUI渲染引擎线程
- 解析HTML, CSS构建DOM树 =》 布局 =》 绘制
- 与JS引擎互斥 即执行JS线程时,GUI线程会pending,当任务队列空闲时才会再执行GUI线程
- JS引擎线程
- 处理js 解析执行脚本
- 分配、处理、执行待执行的事件、event队列
- 阻塞GUI线程渲染
- 定时器触发引擎线程
- 异步定时器处理与执行 setTimeout和setInterval
- 接收js引擎所分配的定时器任务,并计数
- 处理完成后交给事件触发线程触发
- 异步HTTP请求线程
- 异步执行请求类处理,譬如Promise、ajax等
- 接收js引擎分配的异步http请求
- 监听回调,交给事件触发线程触发
- 事件触发引擎线程
- 接收来源: 定时器、异步、用户操作
- 将回调过来的事件依次接入到任务队列队尾,返还给js引擎来执行
2. EVENT-LOOP
a. 执行堆栈
- JS是单线程语言,单步执行
function run() {
func1()
}
function func1() {
func2()
}
function func2() {
throw new Error('please check your call stack')
}
run()
b. 面试题
- js堆栈的执行顺序与堆栈溢出 =》 性能优化
function func() {
func()
}
func()
- 执行顺序
setTimeout(() => {
console.log('Time out')
})
Promise.resolve(1).then(() => {
console.log('promise')
})
console.log('hi')
// h p t
### promise
#### a. 理论
```js
// 1写一个异步定时
setTimeout(()=>{
console.log('Timeout')
}, 2000)
// 2写一个异步请求
request.onreadystatechage = () => {
if(request.readyState === 4) {
const_status = request.state
if(_status === 200) {
const_res = request.responseText
return sucess(_res)
} esle {
return fail(_status)
}
}
}
// 3延时后再请求
setTimeout(()=>{
console.log('Timeout')
request.onreadystatechage = () => {
if(request.readyState === 4) {
const_status = request.state
if(_status === 200) {
const_res = request.responseText
return sucess(_res)
} esle {
return fail(_status)
}
}
}
}, 2000)
// 4再延时再请求 回调地狱
setTimeout(()=>{
console.log('Timeout')
request.onreadystatechage = () => {
if(request.readyState === 4) {
const_status = request.state
setTimeout(()=>{
console.log('Timeout')
request.onreadystatechage = () => {
if(request.readyState === 4) {
const_status = request.state
if(_status === 200) {
const_res = request.responseText
return sucess(_res)
} esle {
return fail(_status)
}
}
}
}, 2000)
if(_status === 200) {
const_res = request.responseText
return sucess(_res)
} esle {
return fail(_status)
}
}
}
}, 2000)
// 5Promise的出现解决回调的流程无穷嵌套
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+500)
}, 1000)
}
}
const p = new Promise((resolve, reject)=>{
resolve(1)
})
p.then(wait500)
.then(wait1000)
.then(wait500)
.then(wait1000)
.then(result => {
console.log('end'+result)
})
// 7全部执行完成后再操作
Promise.all([wait500, wait1000]).then(result=>{
consloe.log('all end', result)
})
// 8一但有执行完成的立刻操作
Promise.race([wait500, wait1000]).then(result=>{
consloe.log('race end', result)
})
// all和race的返回值是什么?
// all返回一个数组包含全部的函数
// race返回一个函数 即先执行完成的函数
b.面试题 手撕一个Promise
描述promise的框架
-
- promise有哪几种状态 - pending、fulfilled、rejected
-
- new Promise执行器executor()执行器参数是什么? - resolve和reject
-
- Promise的默认状态是什么?p promise的状态流转?p到f或r
-
- promise的value保存成功状态的枚举? -undefined、thenable、promsie
-
- 失败状态的值? - reason
描述promise的接口
- 失败状态的值? - reason
-
- promise一定有then,then接收来源? -两个回调 onfulfilled(value)+onrejected(reason)
// 三个状态 PENDING FUIFILLED REJECTED
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
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
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejcted) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejcted(this.reason)
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value)
})
this.onRejectedCallbacks.push(()=>{
onRejcted(this.reason)
})
}
}
}
const promise = new Promise((resolve, reject) => {
resolve('成功')
}).then(data => {})
.catch(err => {})
// 启示 同步 =》 异步
// 顺序和空间的关系
补充知识点
- promise是一个具有then方法的对象,行为遵循promiseA+规范
- thenable是一个有then方法的函数或者对象
- value是promise状态成功时的值,即resolve的参数
- reason是promise状态失败时的值,即reject的参数 表示各种拒绝的原因
- exception异常值
规范
Promise States
有三种状态,
- pending 初始状态 可改变
1.1. 一个promise在resolve或reject之前都处于这个状态
1.2. 通过resolve可以把pendeing状态改为fulfilled状态
1.3. 通过rejecte可以把pending状态改为rejected状态 - fulfilled
2.1 最终态,不可变
2.2 一个promise被resolve后会变成这个状态
2.3 必须拥有一个value - rejected
3.1 最终态,不可变
3.2 一个promise被reject后会变成这个状态
3.3 必须拥有一个reason
pending -> resolve(value) -> fulfilled
pending -> reject(reason) -> rejected
then
promise应该有一个then方法 用来访问最终结果
promise.then(onFulfilled, onRejected)
- 参数要求
1.1 onFulfilled应该是一个函数,如果不是则应该被忽略
1.2 onRejected应该是一个函数,如果不是则应该被忽略 - onFulfilled特性
2.1 当promise状态变成fulfilled时应该调用onFulfilled函数,参数就是value
2.2 promise变成fulfilled之前不应该被调用
2.3 只能被调用一次 - onRejected
3.1 promise状态变成rejected时应该调用onRejected,参数就是reason
3.2 promise状态变成rejected之前不应该被调用
3.3 只能被调用一次 - onFulfilled和onRejected执行环境应该是微任务
- then方法可以被调用多次 ,其实就是链式调用
5.1 promise状态变成fulfilled后,所有的onFulfilled回调都应该按照then的顺序执行
5.2 promise状态变成rejected后,所有的onRejected回调都应该按照then的顺序执行
const promise = new Promise()
promise.then(cb1, cb2)
promise.then(cb1, cb2)
promise.then(cb1, cb2)
- 返回值
then的返回值应该是一个promise,且是一个新的promise
6.1 onFulfilled或者onRejected执行结果是x,调用resolvePromise()
6.2 onFulfilled或者onRejected执行报错,promise2就需要被rejected
6.3 onFulfilled不是一个函数,promise2以promise1的value触发fulfilled
6.4 onRejected不是一个函数,promise2以promise1的reason触发rejected
const promise1 = new Promise()
const promise2 = promise.then(cb1, cb2)
promise2.then()
- resolvePromise
7.1 promise2 === x, reject typeError
7.2 如果x是一个promise
pending
fulfilled
rejected
7.3 对象或函数
let then = x.then
resolvePromsie(promise, x, resolve, reject)