ES6 Promise原理介绍

    在ES6提出Promise之前,异步回调存在回调地狱问题。例如:

    function toUpper(rawString, callback){
        let upperString = rawString.toUpperCase();
        callback(upperString)
    }

    function deleteSpace(rawString, callback) {
        let result =  rawString.replace(/\s*/g,"");
        callback(result)
    }

    function doTasks(rawString){
        toUpper(rawString, function (upperString) {
            deleteSpace(upperString, function (result) {
                console.log('the result is: ' + result);
            })
        })
    }

    doTasks('hello world')

把一个字符串转换成大写,并去掉空格。那么用Promise实现相同功能,写法如下:

    function doAsyncTasks(rawString){
        return new Promise((resolve, reject) => {
            resolve(rawString);
        })
    }

    doAsyncTasks('hellow world').then(function (rawString) {
        return rawString.toUpperCase();
    }).then(function (value) {
        let result = value.replace(/\s*/g,"");
        console.log('async the result is: ' + result)
    })

对比两种写法,用Promise更清晰一些,解决了地狱回调问题。在一些异步加载的场景下,用Promise进行封装,代码看起来也比较清晰好看。例如在加载图片的时候,封装如下:

//HTML
//JavaScript function loadImgAsync (url) { return new Promise((resolve, reject) => { const imgIns = new Image(); imgIns.onload = ()=>{ resolve(imgIns) }; imgIns.onerror = reject; imgIns.src = url; }) } loadImgAsync('./xxx.png').then((imgIns)=>{ console.log(`load img done`) document.getElementById('mainId').appendChild(imgIns) }).catch(()=>{ console.log(`failed to load img`) })

下面简单实现一个Promise,看看Promise实现原理。

    function MyPromise(func) {
        var value = null
        var onFulFilledCallback = [], onRejectedCallback = []
        this.then = (onFulFilled) => {
            //注册回调函数
            onFulFilledCallback.push(onFulFilled)
            return this
        }
        this.catch = (onRejected) => {
            onRejectedCallback.push(onRejected)
            return this
        }
        function resolve(newValue) {
            //加个定时器,保证先注册回调函数,再执行回调
            value = newValue
            setTimeout(() => {
                onFulFilledCallback.forEach((callback) => {
                    callback(value)
                })
            }, 0)
        }
        function reject(newValue) {
            value = newValue
            setTimeout(() => {
                onRejectedCallback.forEach((callback) => {
                    callback(value)
                })
            }, 0)
        }
        func(resolve, reject)
    }

    var myPromise = new MyPromise((resolve, reject) => {
        resolve('2 second fly')
    })
    myPromise.then((value) => {
        console.log(`resolve value: ${value}`)
    })
    myPromise.catch((value) => {
        console.error(`reject value: ${value}`)
    })

代码也比较简单,MyPromise对象的then和catch方法用来注册回调函数。当new MyPromise实例的时候执行传给MyPromise对象构造函数的回调函数,而且这个函数的两个参数是MyPromise对象实现的两个内部函数。注意MyPromise对象中的两个内部函数resolve 和 reject 是异步执行then方法和catch方法注册的回调函数。这样就保证了虽然先执行了resolve(), 后调用then方法,也能正常执行then方法注册的回调函数。

 

你可能感兴趣的:(ES6)