JS-promise源码解析理解

wujiawen 发布于

Promise源码解析

  • 关键点记录
    如何通过then()实现将异步结果返回?

    原理:
    通过三种状态判断异步操作是否已经执行成功

    1
    2
    3
    const PENDING = 'pending'; //初始状态
    const FULFILLED = 'fulfilled'; // 成功状态
    const REJECTED = 'rejected'; // 失败状态

    通过成功回调的数组onResolveCallbacks,以及失败回调的数组onRejectedCallbacks
    存放then()方法接收的回调函数

    执行then()方法之后,如果状态是 pending,则存入回调数组中

    在异步执行完成后,会调用 resolve 以及 reject
    此时,会相应改变状态以及调用回调数组中的回调方法,达到在异步操作完成后执行回调的结果

    then() 会返回 promise 对象

  • then()方法需要生成微任务

  • ES6中的promise实现

    微任务的生成是按照执行环境的不同而使用不同的生成方式

    附上生成部分的源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    let scheduleFlush
    // Decide what async method to use to triggering processing of queued callbacks:
    if (isNode) { // node环境 使用 process.nextTick()
    scheduleFlush = useNextTick()
    } else if (BrowserMutationObserver) {
    scheduleFlush = useMutationObserver() // 浏览器环境 使用MutaionObserver()
    } else if (isWorker) {
    scheduleFlush = useMessageChannel()
    } else if (browserWindow === undefined && typeof require === 'function') {
    scheduleFlush = attemptVertx()
    } else {
    scheduleFlush = useSetTimeout() // 无法判断环境 使用 setTimeout()
    }
  • promise链式调用
    promise.then()返回一个promise对象

    在then()方法里面,return promise2 = new Promise((resolve, reject) => {})

    会先调用promise1的then()方法传入的回调函数 调用完成后,将调用结果 x 作为promise2的值 resolve(x)

  • promise.all()
    返回一个promise,resolve 一个结果数组

    接收一个数组参数

    对数组每一项进行判断并处理
    若是普通值,则直接存放在 result 中
    若是promise,则调用 then() 方法,将结果存放到result

    并且,result 的顺序严格按照传入参数数组的顺序
    (在对参数数组进行遍历操作时,会把下标传递给结果处理函数,存放到 result 的对应位置)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // 封装 Promise.all方法
    Promise.all = function (values) {
    return new Promise((resolve, reject) => {
    let result = [] // 存放返回值
    let counter = 0 // 计数器,用于判断异步完成
    function processData(key, value) {
    result[key] = value
    // 每成功一次计数器就会加1,直到所有都成功的时候会与values长度一致,则认定为都成功了,所以能避免异步问题
    if (++counter === values.length) {
    resolve(result)
    }
    }
    // 遍历 数组中的每一项,判断传入的是否是promise
    for (let i = 0; i < values.length; i++) {
    let current = values[i]
    // 如果是promise则调用获取data值,然后再处理data
    if (isPromise(current)) {
    current.then(data => {
    processData(i, data)
    }, reject)
    } else {
    // 如果不是promise,传入的是普通值,则直接返回
    processData(i, current)
    }
    }
    })
    }

promise简单总结记忆

链式调用需要等待上一个 then() 的微任务完成才会进行注册
若有上一个 then() return 则下一个 then() 需要等 return的内容执行完成才进行注册

参考:
https://github.com/xieranmaya/blog/issues/3

检测(是否理解):
https://blog.csdn.net/lqyygyss/article/details/102662606

Promise/A+ 规范(中文版):
https://www.icode9.com/content-4-365156.html