Understanding of promises and handwritten promises

introduce

Before understanding promise, you should first understand the basic part, which is divided into computer principle, browser principle and JS execution principle

computer principles

process

Definition: A process is the smallest unit of CPU resource allocation - an independent resource

thread

Definition: Thread is the smallest unit of CPU scheduling - shared resource

Related questions

  1. Chrome opens a new window, is the tab page a process or a thread? Answer: Process
  2. How do processes communicate (how do windows communicate)? Answer: Storage (localStorage, sessionStorage, cookie)
  3. Difference between various storages?
  4. Browser principle (mostly middle and high-level management) The browser has multiple threads in a process

Browser Principle

GUI rendering engine

  1. Parse html, css, build dom tree => layout => draw
  2. It is mutually exclusive with the js engine. When the JS engine thread is executed, the GUI will be pending, and will continue to execute the GUI when the task queue is idle.

JS engine thread

  1. Process JS, parse and execute scripts
  2. Allocate, process, and execute events to be executed, event queue
  3. blocking GUI rendering

The timer triggers the engine

  1. setTimeout,setInterval
  2. Receive the timer task assigned by the js engine and count it
  3. After the processing is completed, it is handed over to the event triggering thread to trigger

Asynchronous HTTP request thread

  1. Execute request class processing asynchronously, promise/ajax, etc.
  2. Receive JS engine to dispatch asynchronous HTTP request
  3. Listen to the callback and give it to the event trigger thread to trigger

event trigger engine

  1. Receive source: timer, asynchronous, user action
  2. Connect the callback events to the end of the task queue in turn, and return them to the engine

JS execution principle

Allocate memory

execution stack

Interview question 1: Execution order of js stack, stack overflow (stack burst) => performance
optimization Interview question 2: Array operation return value problem splice split... promise.all promise.race

Task queue
Macro task: macro: script, setTimeout, setInterval, I/O
micro task: new promise{}.then()

There are micro-tasks, and macro-tasks always precede micro-tasks

1. In-depth understanding of promises

promise specification

promise是一个有then方法的对象或者函数,promise有三种状态

状态
  1. pending: 初始状态 - 可改变
  2. fulfilled:最终状态 - 不可改变
  3. rejected:最终状态 - 不可改变
状态变化
  1. pending -> reslove(value) -> fulfilled
  2. pending -> reject(reason) -> rejected
then方法
  1. 参数:onFulfilledonRejected(两个参数必须是函数,如果不是函数,应该被忽略)
  2. onFulfilledonReject是微任务 (js是单线程,分为了同步任务和异步任务,而异步任务中也有优先级,微任务即表示优先级高的)
  3. then方法可以调用多次,用数组来存放多个onFulfilled的回调和onRejected的回调
  4. then方法的返回值是一个新的promise 将onFulfilled或onrejected的返回结果为x,通过resolvePromise来解析promise this.resolvePromise(promise2, x, resolve, reject);

2.一步步实现一个promise

  1. class对象并定义三种状态
  2. constructor中设置初始状态以及定义value和reason
  3. 实现resolve和reject方法,在状态为pending时改变状态
  4. constructor中传一个入参fn,fn接收resolve和reject,若报错则通过reject抛出去
  5. 实现then方法,接收两个参数:then(onFulfilled, onRejected) {}
  6. 检查处理then参数,判断onFulfilled和onRejected是否为函数,若不是函数,则返回value或reason
  7. 定义返回值(promise2)并根据当前promise的状态调用不同的函数
  8. 设置一个状态的监听机制, 当状态变成fulfilled或者rejected后, 再去执行callback
  9. 新建两个数组, 来分别存储成功和失败的回调, 调用then的时候, 如果还是pending就存入数组
  10. 实现getter和setter函数,在给status赋值后, 下面再加一行forEach
  11. 当 onFulfilled 或者 onRejected 抛出异常 e ,则 promise2 拒绝执行,并返回拒因 e。(这样的话, 我们就需要手动catch代码,遇到报错就reject)
  12. 当onFulfilled 或者 onRejected 返回一个值 x ,则运行resolvePromise方法。将realOnFulfilled(this.value)赋值给x,this.resolvePromise(promise2, x, resolve, reject);
  13. 实现resolvePromise方法
  14. onFulfilled 和 onRejected 是微任务,使用queueMicrotask包裹执行函数
  15. 实现catch方法

3.Iterator,Generator和async的理解

Interator迭代器
  1. 是一种的特殊的对象,每一个迭代器对象都有一个next方法,
  2. 每次调用都会返回一个劫夺对象,结果对象中包含两个值:
    value: 当前属性的值;
    done: 判断是否遍历结束
Generator生成器
  1. 生成器时一种返回迭代器的函数,函数中会用到新的关键字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}
复制代码
  1. 注意
  • 每当执行完一条yield语句后函数就会自动停止执行, 直到再次调用next();
  • yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出错误;
  • 可以通过函数表达式来创建生成器, 但是不能使用箭头函数
    let generator = function *(){}

4.面试中可能会遇到的问题

  1. 为什么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

  1. 为什么在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

Guess you like

Origin juejin.im/post/7080141138232868901