认识 Promise() 的原理与实现

Javascript 采用回调函数(callback)来处理异步编程,但多层回调嵌套会形成回调金字塔(Pyramid of Doom)。

于是便有了CommonJS的 Promise/A 规范用于解决回调金字塔问题。

new Promise() 构造函数同步执行,.then() 异步执行。

JavaScript 中一个常见的嵌套回调如下:

// 回调金字塔
asyncOperation(function(data){
    //处理 data
    anotherAsync(function(data2){
        //处理 data2
        yetAnotherAsync(function(){
            //完成
        });
    });
});

引入 Promise 之后:

promiseSomething()
.then(function(data){
    //处理 data
    return anotherAsync();
})
.then(function(data2){
    // 处理 data2
    return yetAnotherAsync();
})
.then(function(){
    // 完成
});

Promise 将嵌套的 callback ,改造成一系列的 .then() 的连缀调用。

在 ES6 中 Promise 提供了以下 API:

(1)构造函数

 function Promise(resolve){}

(2)原型方法

Promise.prototype.then = function(){}

Promise.prototype.catch = function(){}

(3)静态方法

Promise.resolve = function(){}

Promise.reject = function(){}

Promise.all = function(){}

Promise.race = function(){}

promise的核心原理其实就是发布订阅模式,通过两个队列来缓存成功的回调(onResolve)和失败的回调(onReject)。

基于这个原理,我们自己简单实现以下:

function Promise(executor){
    function resolve(value){}
    function reject(value){}
    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}
var promise = new Promise((resolve,reject)=>{
    console.log('start')
})

新的写法: 

const PENDING = 'pending';
const RESOLVE = 'resolve';
const REJECT = 'reject';

class Promise{
    constructor(excutor){
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectCallbacks = [];
        excutor(resolve,reject);
    }
    let resolve = (value)=>{
        if(this.status === PENDING){
            this.status = RESOLVE;
            this.value = value;
            this.onResolvedCallbacks.forEach(fn=>{
                fn()
            });
            
        }
    }
    let reject = ()=>{
        if(this.status === PENDING){
            this.status = REJECT;
            this.reason = reason;
            this.onRejectCallbacks.forEach(fn=>{
                fn()
            });
        }
    }

    then(onFulfilled,onReject){
        if(this.status === RESOLVE){
            onFulfilled(this.value);
        }else if(this.status === REJECT){
            onReject(this.reason);
        }else if(this.status === PENDING){
            this.onResolvedCallbacks.push(()=>{// Aop
                //todo
                onFulfilled(this.value)
                
            })
            this.onRejectCallbacks.push(()=>{
                onReject(this.reason)
            })
        }       
    }

}

其他补充:

<div id="test-promise-log"></div>

<script>

//清除log
var logging = document.getElementById('test-promise-log');
while(logging.children.length > 1){
    logging.removeChild(logging.children[logging.children.length - 1]);
}
//输出log
function logs(s){
    var p = document.createElement('p');
    p.innerHTML  = s;
    logging.appendChild(p);
}

//
new Promise(function(resolve,reject){
    logs('start new Promise');
    var timeOut = Math.random()*2;
    console.log('set timeout to:'+ timeOut + ' seconds.');
    setTimeout(function(){
        if (timeOut < 1){
            console.log('call resolve() ...');
            resolve('200 OK');
        } else{
            console.log('call reject() ...');
            reject('timeout in '+ timeOut + 'seconds');
        }
    },timeOut*1000)
}).then(function(r){
    console.log('Done:' + r);
}).catch(function(reason){
    console.log('Failed: ' + reason)
});

//
function multiply(input){
    return new Promise(function(access,rejecrt){
        console.log('calculating ' + input + 'x' + input + '...');
        setTimeout(access,500,input*input);
    });
}
//
function add(input){
    return new Promise(function(resolce,reject){
        console.log('calculating ' + input + '+' + input + '...');
        setTimeout(resolce,500,input + input);
    });
}
var p = new Promise(function(resolve,reject){
    console.log('start new Promise ...');
    resolve(123);
}).then(multiply)
    .then(add)
    .then(multiply)
    .then(add)
    .then(function(result){
        console.log('Got Value: ' + result);
    })

// AJAX异步执行函数转换为Promise对象
function ajax(method,url,data){
    var request = new XMLHttpRequest();
    return new Promise(function(resolve,reject){
        request.onreadystatechange = function(){
            if (request.readyState === 4){
                if (request.status === 200) {
                    resolve(request.responseText);
                }else{
                    reject(request.status);
                }
            }
        };
        request.open(method,url);
        request.send(data);
    });
}
var p = ajax('GET','url');
p.then(function(text){
    console.log(text);
}).catch(function(status){
    console.log('ERROR: ' + status);
})
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值