promise对象的深入解析(附示例)

本篇文章给大家带来的内容是关于promise对象的深入解析(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

js中的异步,刚开始的时候都是用回调函数实现的,所以如果异步嵌套的话,就有出现回调地狱,使得代码难以阅读和难以维护,后来es6出现了promise,解决了回调地狱的问题。现在我们就自己写代码实现一下promise,这样才能深入理解promise的运行机制,对以后使用promise也能够更加得心应手。开始之前可以先看下promise的官网promise/A+

先来看下promise的用法

new Promise((resolve,reject)=>{  resolve(1);  reject(11);}).then(res=>{  console.log(res);  setTimeout(()=>{    return new Promise((resolve,reject)=>{        resolve(2)    })   },1000)}).then(res2=>{  console.log(res2);});

登录后复制

控制台打印
1
…1s later
2

先分析下上面这段代码,先提出几个问题
1.第一段resolve和reject都有,但是只输出了1,为什么?
2.then里的res是如何取到resolve中的值的?
3.promise是如何做到链式调用的?

状态机

promise中有个状态机的概念,先说下为什么要有状态机的概念呢,因为promise的状态是单向变化的,有三种状态,pending,fullfilled,rejected,而这三种状态只能从pending->fullfilled或者pending->rejected这两种形式,也就是说执行了fullfilled之后,就不会执行rejected。这就解释了上面的第一个问题。

下面我们来看下具体实现的完整代码

const PENDING = 'PENDING';const FULLFILLED = 'FULLFILLED';const REJECTED = 'REJECTED';    class Promise{    constructor(fn){       this.status = PENDING;//状态        this.data = undefined;//返回值        this.defercb = [];//回调函数数组        //执行promise的参数函数,并把resolve和reject的this绑定到promise的this        fn(this.resolve.bind(this),this.reject.bind(this));    }    resolve(value){        if(this.status === PENDING){            //只能pending=>fullfied            this.status = FULLFILLED;            this.data = value;            this.defercb.map(item=>item.onFullFilled());        }    }    reject(value){        if(this.status === PENDING){            //只能pending=>rejected            this.status = REJECTED;            this.data = value;            this.defercb.map(item=>item.onRejected());        }    }    then(resolveThen,rejectThen){       //如果没有resolveThen方法,保证值可以穿透到下一个then里有resolveThen的方法中        resolveThen = typeof resolveThen === 'function' ? resolveThen : function(v) {return v};        rejectThen = typeof rejectThen === 'function' ? rejectThen : function(r) {return r};        //返回的都是promise对象,这样就可以保证链式调用了        switch(this.status){            case PENDING:            return new Promise((resolve,reject)=>{                const onFullFilled = () => {                    const result = resolveThen(this.data);//这里调用外部then的resolveThen方法,将值传回去                    //如果返回值是promise对象,执行then方法,取它的结果作为新的promise实例的结果,因为this.data会重新赋值                    result instanceof Promise && result.then(resolve,reject);                }                const onRejected = ()=>{                    const result = rejectThen(this.data);                    result instanceof Promise && result.then(resolve,reject);                }                this.defercb.push({onFullFilled,onRejected});            });            break;            case FULLFILLED:               return new Promise((resolve,reject)=>{                     const result = resolveThen(this.data);                     result instanceof Promise && result.then(resolve,reject);                     resolve(result);               })            break;            case REJECTED:               return new Promise((resolve,reject)=>{                   const result = rejectThen(this.data);                   result instanceof Promise && result.then(resolve,reject);                   reject(result)               })               break;        }    }}

登录后复制

运行下面的例子

new Promise((resolve, reject) => {    setTimeout(() => {        resolve(1);    }, 1000);}).then((res2) => {    console.log(res2);    return new Promise((resolve, reject) => {        setTimeout(() => {            resolve(2);        }, 1000);    });}).then((res3) => {    console.log(res3);    return new Promise((resolve, reject) => {        setTimeout(() => {            resolve(3);        }, 1000);    });}).then((res4) => {    console.log(res4);});

登录后复制

控制台打印
…1s later
1
…1s later
2
…1s later
3
说明上面的实现是没有问题的
不过还有一个问题,就是事件循环的顺序问题,比如执行下面的代码

new Promise((resolve) => {    resolve();}).then(() => {    console.log('1');}).then(() => {    console.log('2');});console.log('3');

登录后复制

并没有像预想中输出3,1,2,而是输出了1,2,3,原因就是因为我们的这个Promise是在主线程中,没有在下一个任务队列中,可以加上settimeout解决这个问题,不过这也只是为了让我们更好理解执行顺序而已,然而实际上是promise是属于微任务中的,而settimeout是属于宏任务,还是不太一样的

以上就是promise对象的深入解析(附示例)的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2736432.html

(0)
上一篇 2025年3月8日 01:24:28
下一篇 2025年3月8日 01:24:37

AD推荐 黄金广告位招租... 更多推荐

相关推荐

发表回复

登录后才能评论