Promise的使用及原理(一):简单的promise使用及异步处理

1、简单的promise使用
    let p = new Promise(function (resolve, reject) {
        console.log("start");
        resolve("成功的回调");
        // reject("失败的回调");
    });
    p.then((data) => {
        console.log("success---"+data);
    }, (err) => {
        console.log("error---"+err);
    });
    console.log("end" );

执行上面的代码,输出为:

start
end
success---成功的回调

由此可见:

  • 1)我们在new一个Promise时,需要传递一个excutor执行器(函数),会立即被调用,这个执行器接收两个参数,分别为resolve和reject方法;调用resolve方法表示成功,调用reject方法表示失败;
  • 2)同时返回的promise实例,会有一个then方法,then方法中传递两个参数,分别是成功的回调和失败的回调函数

除上述之外,我们还应了解Promise状态:

  • promise实例一共具有三种状态
    • 异步操作未完成(pending)
    • 异步操作成功(fulfilled)
    • 异步操作失败(rejected)
  • 其中这三种状态的变化途径只有两种:
    • 异步操作成功,从“未完成”到“成功”,即状态由pending变为fulfilled;
    • 异步操作失败,从“未完成”到“失败”,即状态由pending变为rejected;

代码如下:

    class Promise {
        constructor(fn){
            this.data = undefined;   // 回调成功的data
            this.error = undefined;  // 失败回调的error
            this.status = "pending";
            // 下面在fn中传入resolve和reject方法时,需要进行this绑定,否则在resolve和reject方法中获取到的this为undefined
            fn(this.resolve.bind(this), this.reject.bind(this));
        }
        resolve(data){
            if (this.status === "pending") {
                // 重置状态为fulfilled,并置this.data为获取的数据
                this.status = "fulfilled";
                this.data = data;
            }
        }
        reject(error){
            // 重置状态为rejected,并置this.error为错误信息
            if (this.status === "pending") {
                this.status = "rejected";
                this.error = error;
            }
        }
        then(onfulfilled,onrejected){
            // 当状态为fulfilled时,执行成功的回调
            if(this.status === "fulfilled"){
                onfulfilled(this.data);
            }
            // 当状态为rejected时,执行成功的回调
            if (this.status === "rejected"){
                onrejected(this.error);
            }
        }
    }
    
    module.exports = Promise;
2、promise的异步处理
  • 我们知道,promise的主要作用是用于处理异步函数,在以往的异步中,比如我们有一个ajax请求中传递参数,但是这个参数来源于另一个ajax的返回值,那么就会有了如下代码:
$.ajax({
    url:url1,
    success:function (data) {
        $.ajax({
            url:url2,
            data:data,
            success:function () {
            }
        })
    }
});
  • 如果一层嵌套还好,但如果出现多层,代码就会看起来很庞大,就产生了回调地狱,如果使用promise的话,代码就会看起来整齐很多。下面我们首先实现promise中异步处理。

  • 如下代码,如果使用官网的Promise,会有如下输出:

    let Promise = require("./promise");
    let p = new Promise(function (resolve, reject) {
        console.log("start");
        setTimeout(() => {
            resolve("成功的回调");
        },1000)
        // reject("失败的回调");
    });
    p.then((data) => {
        console.log("success---"+data);
    }, (err) => {
        console.log("error---"+err);
    });
    console.log("end" );

输出结果如下:

    start
    end
    success---成功的回调     // 1s后输出
  • 但是如果使用上面我们写的promise,会发现,只有start和end输出,这是由于:

    1)promise中excutor执行完之后,由于异步那么resolve函数还未执行

    2)此时就会执行promise实例上的then方法,此时promise的status状态为pending状态,自然也不会执行onfulfilled与onrejected方法

    3)待1s过后,执行resolve方法,将status的状态置为fulfilled状态,程序运行结束

  • 为了解决上面的问题,我们可以在then方法中,如果此时处于pending状态,可以将onfulfilled与onrejected方法存放于一个数组中,在执行到resolve或者reject方法时,再执行then中传递的方法,

  • 之所以放于数组中,是由于对于同一个promise实例,then方法可以被多次调用;如果只保存当前函数,那么执行多个then方法时,不能保证所有then方法中的onfulfilled或onrejected都被执行到

  • 代码如下:

    class Promise {
        constructor(fn){
            this.data = undefined;   // 回调成功的data
            this.error = undefined;  // 失败回调的error
            this.status = "pending";
            this.onResolvedCallbacks = [];
            this.onRejectedCallbacks = [];
            // 下面在fn中传入resolve和reject方法时,需要进行this绑定,否则在resolve和reject方法中获取到的this为undefined
            fn(this.resolve.bind(this), this.reject.bind(this));
        }
        resolve(data){
            if (this.status === "pending") {
                // 重置状态为fulfilled,并置this.data为获取的数据
                this.status = "fulfilled";
                this.data = data;
                this.onResolvedCallbacks.forEach(fn => {
                    fn();
                })
            }
        }
        reject(error){
            // 重置状态为rejected,并置this.error为错误信息
            if (this.status === "pending") {
                this.status = "rejected";
                this.error = error;
                this.onRejectedCallbacks.forEach(fn => {
                    fn();
                })
            }
        }
        then(onfulfilled,onrejected){
            // 当状态为fulfilled时,执行成功的回调
            if(this.status === "fulfilled"){
                onfulfilled(this.data);
            }
            // 当状态为rejected时,执行成功的回调
            if (this.status === "rejected"){
                onrejected(this.error);
            }
            // 当状态为pending时,那么将onfulfilled与onrejected方法进行存储,在执行resolve或者reject时进行执行
            if(this.status === "pending"){
                // 这里push onfulfilled 与 onrejected 方法时,不直接push,而是push一个函数,在函数中执行onfulfilled 与 onrejected是为了获取resolve或者reject函数中传递的data或者error
                this.onResolvedCallbacks.push(() => {
                    onfulfilled(this.data);
                });
                this.onRejectedCallbacks.push(() => {
                    onrejected(this.error);
                });
            }
        }
    }
    
    module.exports = Promise;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值