introducir
Antes de comprender la promesa, primero debe comprender la parte básica, que se divide en el principio de la computadora, el principio del navegador y el principio de ejecución de JS.
principios de la computadora
proceso
Definición: Un proceso es la unidad más pequeña de asignación de recursos de CPU: un recurso independiente
hilo
Definición: Thread es la unidad más pequeña de programación de CPU: recurso compartido
Preguntas relacionadas
- Chrome abre una nueva ventana, ¿la página de pestañas es un proceso o un hilo? Respuesta: Proceso
- ¿Cómo se comunican los procesos (cómo se comunican las ventanas)? Respuesta: almacenamiento (localStorage, sessionStorage, cookie)
- ¿Diferencia entre varios almacenamientos?
- Principio del navegador (principalmente gestión de nivel medio y alto) El navegador tiene varios subprocesos en un proceso
Principio del navegador
motor de renderizado GUI
- Analizar html, css, construir dom tree => diseño => dibujar
- Es mutuamente excluyente con el motor js.Cuando se ejecuta el subproceso del motor JS, la GUI estará pendiente y continuará ejecutándose cuando la cola de tareas esté inactiva.
Hilo del motor JS
- Procesar JS, analizar y ejecutar scripts
- Asignar, procesar y ejecutar eventos para ser ejecutados, cola de eventos
- bloqueando la representación de GUI
El temporizador activa el motor.
- establecer tiempo de espera, establecer intervalo
- Recibir la tarea del temporizador asignada por el motor js y contarla
- Una vez que se completa el procesamiento, se entrega al subproceso de activación del evento para activar
Subproceso de solicitud HTTP asíncrono
- Ejecute el procesamiento de clase de solicitud de forma asíncrona, promesa/ajax, etc.
- Reciba el motor JS para enviar una solicitud HTTP asíncrona
- Escuche la devolución de llamada y déselo al hilo de activación del evento para activar
motor de activación de eventos
- Fuente de recepción: temporizador, asíncrono, acción del usuario
- Conecte los eventos de devolución de llamada al final de la cola de tareas y devuélvalos al motor
Principio de ejecución JS
Asignar memoria
pila de ejecución
Pregunta de la entrevista 1: orden de ejecución de la pila js, desbordamiento de la pila (explosión de la pila) =>
optimización Pregunta de la entrevista 2: operación de matriz problema de valor de retorno división de empalme... promesa.todo promesa.carrera
Cola de tareas
Macro tarea: macro: script, setTimeout, setInterval, I/O
micro tarea: nueva promesa{}.then()
Hay microtareas, y las macrotareas siempre preceden a las microtareas
1. Comprensión profunda de las promesas
especificación de la promesa
promise是一个有then方法的对象或者函数,promise有三种状态
状态
- pending: 初始状态 - 可改变
- fulfilled:最终状态 - 不可改变
- rejected:最终状态 - 不可改变
状态变化
- pending -> reslove(value) -> fulfilled
- pending -> reject(reason) -> rejected
then方法
- 参数:
onFulfilled
和onRejected
(两个参数必须是函数,如果不是函数,应该被忽略) onFulfilled
和onReject
是微任务 (js是单线程,分为了同步任务和异步任务,而异步任务中也有优先级,微任务即表示优先级高的)- then方法可以调用多次,用数组来存放多个onFulfilled的回调和onRejected的回调
- then方法的返回值是一个新的promise 将onFulfilled或onrejected的返回结果为x,通过
resolvePromise
来解析promisethis.resolvePromise(promise2, x, resolve, reject);
2.一步步实现一个promise
- class对象并定义三种状态
- 在
constructor
中设置初始状态以及定义value和reason - 实现resolve和reject方法,在状态为pending时改变状态
- 在
constructor
中传一个入参fn,fn接收resolve和reject,若报错则通过reject抛出去 - 实现then方法,接收两个参数:
then(onFulfilled, onRejected) {}
- 检查处理then参数,判断onFulfilled和onRejected是否为函数,若不是函数,则返回value或reason
- 定义返回值(promise2)并根据当前promise的状态调用不同的函数
- 设置一个状态的监听机制, 当状态变成fulfilled或者rejected后, 再去执行callback
- 新建两个数组, 来分别存储成功和失败的回调, 调用then的时候, 如果还是pending就存入数组
- 实现getter和setter函数,在给status赋值后, 下面再加一行forEach
- 当 onFulfilled 或者 onRejected 抛出异常 e ,则 promise2 拒绝执行,并返回拒因 e。(这样的话, 我们就需要手动catch代码,遇到报错就reject)
- 当onFulfilled 或者 onRejected 返回一个值 x ,则运行
resolvePromise
方法。将realOnFulfilled(this.value)
赋值给x,this.resolvePromise(promise2, x, resolve, reject);
- 实现resolvePromise方法
- onFulfilled 和 onRejected 是微任务,使用queueMicrotask包裹执行函数
- 实现catch方法
3.Iterator,Generator和async的理解
Interator迭代器
- 是一种的特殊的对象,每一个迭代器对象都有一个next方法,
- 每次调用都会返回一个劫夺对象,结果对象中包含两个值:
value: 当前属性的值;
done: 判断是否遍历结束
Generator生成器
- 生成器时一种返回迭代器的函数,函数中会用到新的关键字
yield
,使用function*来创建
function* generator() {
const list = [1, 2, 3];
for (let i of list) {
yield i;
}
}
let g = generator();
console.log(g.next()); // {value: 1, done: false}
console.log(g.next()); // {value: 2, done: false}
console.log(g.next()); // {value: 3, done: false}
console.log(g.next()); // {value: undefined, done: true}
复制代码
- 注意
- 每当执行完一条yield语句后函数就会自动停止执行, 直到再次调用next();
- yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出错误;
- 可以通过函数表达式来创建生成器, 但是不能使用箭头函数
let generator = function *(){}
4.面试中可能会遇到的问题
- 为什么promise resolve了一个value, 最后输出的value值确是undefined
const test = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000);
}).then((value) => {
console.log('then');
});
setTimeout(() => {
console.log(test);
}, 3000)
复制代码
答:因为在.then中没有return则相当于return undefined,所以value是undefined
- 为什么在catch的回调里, 打印promise, 显示状态是pending
const test = new MPromise((resolve, reject) => {
setTimeout(() => {
reject(111);
}, 1000);
}).catch((reason) => {
console.log('报错' + reason);
console.log(test)
});
setTimeout(() => {
console.log(test);
}, 3000)
复制代码
答:catch函数会返回一个新的名为test的promise函数,在catch中还没有执行完成,所以是pending