js中Promise的原理及实现

结合MDN文档及b站学习视频掌握Promise的原理和实现

先明白以下几个问题:

Promise是什么?
Promise是javascript的一个内置对象,语法上是一个构造函数。

Promise的作用
(1)使回调函数更加灵活,不需提前指定回调函数。
(2)支持链式调用,封装异步操作,解决回调地狱。

回调地狱的缺点
(1)代码不便阅读和维护
(2)需要逐层处理异常,没有异常传透功能

Promise的特点:
(1)有三种状态
pending: 初始状态,既不是成功,也不是失败状态。
resolved(fulfilled): 意味着操作成功完成。
rejected: 意味着操作失败。
只有内部执行函数的执行结果能决定状态的变化。
(2)一旦状态改变就不可再变。

使用方法举例:

//初始状态为pending
var pro = new Promise(resolve,reject)=>{
	resolve(value);//若执行成功函数,则状态变为resolved
	reject(reason);//若执行失败函数,则状态变为rejected
	});
pro.then(fn1,fn2);//fn1:成功时的执行函数,fn2:失败时的执行函数

例:用Promis封装ajax

var ajax = function(url) {
    return new Promise(function(resolve, reject) {
        var xhr = new XMLHttpRequest();
        xhr.open('get', url, true);
        xhr.send();
        xhr.onreadystatechange = function() {
            if (xhr.readystate == 4 && xhr.status == 200) {
                resolve(xhr.responseText)
            } else if (xhr.readystate == 4 && xhr.status !== 200) {
                reject(xhr.statusText)
            }
        }
    })
}
ajax.then(console.log(xhr.responseText)); //打印出返回的数据

下面开始逐步实现Promise

1.构造函数主体:传入参数为一个执行器函数executor,executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用executor。

function Promise(excutor) {
    const self = this;

    self.status = pending; //记录Promise状态
    self.data = undefined;  //保存成功或失败时参数
    self.callbacks = []; //保存回调函数

    try {
        excutor(resolve, reject);
    } catch (error) {
        reject(error);
    } //捕获异常处理,若发现抛出异常,直接执行失败函数

    function resolve(value) { //成功函数,状态由pending->resolved,并执行成功时函数
        if (self.status !== pending) {
            return
        }//若状态不为pending,则不能再改,直接返回
        
        self.status = resolved;
        self.data = value;
        if (self.callbacks.length > 0) {
            setTimeout(() => { //模拟异步,非源码实现原理
                self.callbacks.forEach(callbacksObj => {
                    callbacksObj.onResolved(value)
                });
            })
        }
    }

    function reject(reason) {//失败函数,状态由pending->rejected,并执行失败时函数
        if (self.status !== pending) {
            return
        }//若状态不为pending,则不能再改,直接返回

        self.status = rejected;
        self.data = reason;
        if (self.callbacks.length > 0) {
            setTimeout(() => {
                self.callbacks.forEach(callbacksObj => {
                    callbacksObj.onRejected(value)
                });
            })
        }
    }
}

2.Promise原型上的then方法(核心)

Promise.prototype.then = function(onResolved, onRejected) {
    const self = this;

    onResolved = typeof onResolved === 'function' ? onResolved : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; //异常传透核心

    return new Promise((resolve, reject) => {
    //执行成功或失败时的回调函数并根据结果返回新的Promise对象
        function handle(callback) {
            try {
                const result = callback(self.data)
                if (result instanceof Promise) {
                    result.then(resolve, reject)
                } else {
                    resolve(result)
                }
            } catch (error) {
                reject(error)
            }
        }
    //若状态还未改变,先将回调函数保存起来
        if (self.status === pending) {
            self.callbacks.push({
                onResolved(value) {
                    handle(onResolved)
                },
                onRejected(reason) {
                    handle(onRejected)
                }
            })
        } else if (self.status === resolved) {
            setTimeout(() => {
                handle(onResolved);
            })
        } else {
            setTimeout(() => {
                handle(onRejected);
            })
        }
    })
}

3.Promise原型上的catch方法

Promise.prototype.catch = function(onRejected) {
    return this.then(undefined, onRejected)
} //执行失败时函数

4.Promise.resolved()和Promise.rejected()

Promise.resolved = function(value) {
    return new Promise((resolve, reject) => {
        if (value instanceof Promise) {
            value.then(resolve, reject)
        } else {
            resolve(value)
        }
    })
} //直接将Promise状态变为resolved

Promise.rejected = function(value) {
    return new promised((resolve, reject) => {
        reject(reason)
    })
} //直接将Promise状态变为rejected

5.Promise.all()
这个方法返回一个新的promise对象,该promise对象在参数对象promises里所有的promise对象都成功的时候才会触发成功,一旦有任何一个promises里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含promises里所有promise返回值的数组作为成功回调的返回值,顺序跟promises的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。

//chuang
Promise.all = function(promises) {
    const values = new Array(promises.length)
    let resolveCount = 0
    return new Promise((resolve, reject) => {
        promises.forEach((p, index) => {
            Promise.resolve(p).then(
                value => {
                    resolveCount++;
                    values[index] = value
                    if (resolveCount === promises.length) {
                        resolve(values)
                    }
                },
                reson => {
                    reject(reason)
                }
            )
        })
    })

}

6.Promise.race()
谁先出结果就由谁决定;
当promises参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。

Promise.race = function(promises) {
    return new Promise((resolve, reject) => {
        promises.forEach((p, index) => {
            Promise.resolve(p).then(
                value => {
                    resolve(value)
                },
                reason => {
                    reject(reason)
                }
            )
        })
    })
}

完整版代码:

function Promise(excutor) {
    const self = this;

    self.status = pending;
    self.data = undefined;
    self.callbacks = [];

    try {
        excutor(resolve, reject);
    } catch (error) {
        reject(error);
    }

    function resolve(value) {
        if (self.status !== pending) {
            return
        }

        self.status = resolved;
        self.data = value;
        if (self.callbacks.length > 0) {
            setTimeout(() => {
                self.callbacks.forEach(callbacksObj => {
                    callbacksObj.onResolved(value)
                });
            })
        }
    }

    function reject(reason) {
        if (self.status !== pending) {
            return
        }

        self.status = rejected;
        self.data = reason;
        if (self.callbacks.length > 0) {
            setTimeout(() => {
                self.callbacks.forEach(callbacksObj => {
                    callbacksObj.onRejected(value)
                });
            })
        }
    }
}
Promise.prototype.then = function(onResolved, onRejected) {
    const self = this;

    onResolved = typeof onResolved === 'function' ? onResolved : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    return new Promise((resolve, reject) => {
        function handle(callback) {
            try {
                const result = callback(self.data)
                if (result instanceof Promise) {
                    result.then(resolve, reject)
                } else {
                    resolve(result)
                }
            } catch (error) {
                reject(error)
            }
        }

        if (self.status === pending) {
            self.callbacks.push({
                onResolved(value) {
                    handle(onResolved)
                },
                onRejected(reason) {
                    handle(onRejected)
                }
            })
        } else if (self.status === resolved) {
            setTimeout(() => {
                handle(onResolved);
            })
        } else {
            setTimeout(() => {
                handle(onRejected);
            })
        }
    })
}

Promise.prototype.catch = function(onRejected) {
    return this.then(undefined, onRejected)
}

Promise.resolved = function(value) {
    return new Promise((resolve, reject) => {
        if (value instanceof Promise) {
            value.then(resolve, reject)
        } else {
            resolve(value)
        }
    })
}

Promise.rejected = function(value) {
    return new promised((resolve, reject) => {
        reject(reason)
    })
}

Promise.all = function(promises) {
    const values = new Array(promises.length)
    let resolveCount = 0
    return new Promise((resolve, reject) => {
        promises.forEach((p, index) => {
            Promise.resolve(p).then(
                value => {
                    resolveCount++;
                    values[index] = value
                    if (resolveCount === promises.length) {
                        resolve(values)
                    }
                },
                reson => {
                    reject(reason)
                }
            )
        })
    })

}

Promise.race = function(promises) {
    return new Promise((resolve, reject) => {
        promises.forEach((p, index) => {
            Promise.resolve(p).then(
                value => {
                    resolve(value)
                },
                reason => {
                    reject(reason)
                }
            )
        })
    })
}

注:更多细节请自行学习相关视频和文档
参考文档:MDN文档中的Promise
参考学习视频:尚硅谷Promoise教程

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Promise、async和await是JavaScript用于处理异步操作的关键字。它们的实现原理如下: 1. PromisePromise是一种表示异步操作的对象,它包含三种状态(pending、fulfilled、rejected)。当一个异步操作完成时,Promise可从pending状态转变为fulfilled状态,表示操作成功;或者从pending状态转变为rejected状态,表示操作失败。Promise提供了then方法来处理操作的结果,并可以进行链式调用。 2. async/await:async函数是Generator函数的一种语法糖,用来简化异步操作的处理。通过在函数前添加async关键字,函数返回值将被自动封装成Promise对象。await关键字只能在async函数使用,用于暂停async函数的执行,等待Promise对象的状态改变后再继续执行。当await后面的异步操作完成时,它会返回Promise对象的结果。 下面以一个获取用户信息的案例来分析Promise、async和await的用法: 使用Promise实现: ``` function getUserInfo() { return new Promise((resolve, reject) => { setTimeout(() => { const user = { name: 'John', age: 25 }; resolve(user); }, 1000); }); } getUserInfo() .then(user => { console.log(user); }) .catch(error => { console.error(error); }); ``` 使用async/await实现: ``` function getUserInfo() { return new Promise((resolve, reject) => { setTimeout(() => { const user = { name: 'John', age: 25 }; resolve(user); }, 1000); }); } async function displayUserInfo() { try { const user = await getUserInfo(); console.log(user); } catch (error) { console.error(error); } } displayUserInfo(); ``` 以上两种方式都可以获取用户信息,并在操作完成后打印到控制台。使用async/await可以使代码看起来更加简洁和易读。通过在async函数内部使用await关键字,可以将异步操作的代码写成类似同步代码的形式,提高了代码的可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值