以最轻量的方式解释Promise

接触过JS的开发人员应该都有用过Promise处理异步编程,它在语法上非常直观的用“then”去对当下所要做得执行和在期之后所要执行的代码做了封装。

function test() {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('after one second');
        }, 1000);
    })

    return promise;
}

test().then(res => {
    console.log(res); 
})

console.log("before one second");

// "before one second"
// "after one second"

对没有接触过异步编程的工程师来讲,这看起来似乎有魔术般的效应,仿佛是将时间做了停顿。不过花点心思去想Promise的内部机制,大家就会发现,它的核心在于巧妙地应用高阶函数的理念将异步操作进行了封装。如果用最轻量的方法趋势线上图的Promise功能,其实几行代码便可以解决。

function Promice(fn) {
    var self = this
    self.status = 'pending' // Promise当前的状态
    self.data = undefined // Promise的值
    self.onResolvedCallback = undefined //回调函数

    function resolve(value) {
        if (self.status === 'pending') {
            self.status = 'resolved'
            self.data = value
            if(self.onResolvedCallback) {
                self.onResolvedCallback(value)
            }
        }
    }

    try { 
        fn(resolve) 
    } catch (e) {
        reject(e)
    }
}

在这里我将reject抓错机制去除,针对去看Promise是如何"控制"异步操作的。上图需要注意的是两个重点:1. status状态去跟踪异步操作是否完成。2. resolve函数要做的就是更新状态并且调用用户指定的fn回调函数。有人可能会问:“如果只是单纯的更新状态,如何保证异步操作已经完成呢?”。这里要注意的是,从Promise得操作说明上,resolve永远只会在异步回调函数里出现,所以当resolve启动时,必然表示异步操作已完成。

有人会注意到onResolvedCallback赋值并没有在代码里实现。这表示在resolve被调用之前,还会有其他的操作执行,也就是"then"函数。

Promice.prototype.then = function (onResolved) {
    var self = this
    var promise2

    if (self.status === 'resolved') {
        return promise2 = new Promice(function (resolve, reject) {
            var x = onResolved(self.data)
            if (x instanceof Promice) { 
                x.then(resolve, reject)
            }
            resolve(x) 
        })
    }

    if (self.status === 'pending') {
        return promise2 = new Promice(function (resolve, reject) {
            self.onResolvedCallback = function (value) {
                var x = onResolved(self.data)
                if (x instanceof Promice) {
                    x.then(resolve, reject)
                }
            }
        })
    }
}

then函数其实在一开始就被调用了,它的责任是去查看status。如果status表明一步操作已经完成,但就直接调用fn。如果还在待定(pending),则将函数赋值给onResolveCallback。当resolve触发时必会做处理。

总结:Promise会给很多人带来一种时间被控制的假象,但底层核心逻辑并不复杂。这里需要注意的是then函数很容易被视为一个异步操作结束后调用的函数,但这明显是个错误的想法。then通常在异步操作之前已经调用,他的任务往往是将传入的回调函数放到resolve可以获取到的作用域。虽然Promise产生的假象能让我们更直观的去开发,但也需要了解的是它的底层实现。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章