promise的自定义代码实现

作者:神秘网友 发布时间:2021-02-28 13:50:02

promise的自定义代码实现

promise的几个关键问题

  1. 如何改变 promise 的状态

    (1) resolve(value): 如果当前是 pending 就会变为 resolved
    (2) reject(reason): 如果当前是 pending 就会变为 rejected
    (3) 抛出异常: 如果当前是 pending 就会变为 rejected

  2. 一个 promise 指定多个成功/失败回调函数, 都会调用吗

    当 promise 改变为对应状态时都会调用

  3. 改变 promise 状态和指定回调函数谁先谁后

    (1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
    (2) 如何先改状态再指定回调
    ① 在执行器中直接调用 resolve()/reject()
    ② 延迟更长时间才调用 then()
    (3) 什么时候才能得到数据
    ① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    ② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

  4. promise.then()返回的新 promise 的结果状态由什么决定

    (1) 简单表达: 由 then()指定的回调函数执行的结果决定
    (2) 详细表达:
    ① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
    ② 如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
    ③ 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果

  5. promise 如何串连多个操作任务

    (1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
    (2) 通过 then 的链式调用串连多个同步/异步任务

  6. promise 异常传透

    (1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
    (2) 前面任何操作出了异常, 都会传到最后失败的回调中处理

  7. 如何中断 promise 链

    (1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
    (2) 办法: 在回调函数中返回一个 pendding 状态的 promise 对象

  8. then等方法为什么要定义在原型上

    (1)当方法定义在构造函数内部的this上时,在实例化多个对象的时候,同样的会把方法也会复制一遍(即每个实例化后的对象,都有一个方法),这样的话,当需要该构造函数实例化很多对象的时候,每一个实例化后的对象的方法都要占用一定的内存,这样就会导致内存开销太大了

    (2)而通过prototype来定义的方法,在实例化对象的时候,都只是在每个对象中复制了一个指向该方法的一个指针,所以实际上,占用的内存只有一个方法

    (3)所以对比两者的话,使用prototype来定义方法的话,可以节省很多的内存开销。但是,在构造函数里面,定义的变量有私有变量(即通过var 定义的变量)和公有变量(即通过this来定义的变量),因为私有变量不能被外界访问,所以我们需要有可以在外界访问私有变量的途径,而在构造函数里面通过this定义的方法可以有效的访问私有变量

  9. Promise then中回调为什么是异步执行

    回调(例如 then 中的)如果可能同步、也可能异步,执行顺序就变成了不确定的,无法保证程序逻辑的一致性 ,也就类似多线程中的竞态条件。为了避免这种不确定性,then 的回调总是作为 Job Queue 中的下一个 Job 执行(异步执行)。

    例如:

    promise.then(function(){ 
      if (trueOrFalse) { 
        // 同步执行 
        foo(); 
      } else { 
        // 异步执行 (如:使用第三方库)
         setTimeout(function(){ 
            foo(); 
         }) 
      } 
    }); 
    
    bar();
    
    1. 如果 promise then 回调是同步执行的,请问 foo() 和 bar() 函数谁先执行 答案是,如果 trueOrFalse 为 true 则 foo() 先执行,bar() 后执行;否则 bar() 先执行,foo() 后执行。在大部分情况下,你没法预料到 trueOrFalse 的值,这也就意味着,你不能确定这段代码真正的执行顺序,这可能会导致一些难以想到的 bug。

    2. 如果 promise then 回调是异步执行的,请问 foo() 和 bar() 函数谁先执行 答案一目了然,bar() 先执行,foo() 后执行。

      所以为了保证代码执行顺序的一致性, then 回调必须保证是异步的。

    promise的代码实现

    //Promise是一个构造函数
    //打印原生Promise发现[[PromiseState]],[[PromiseResult]]都是有双中括号的,表明这两个属性都是内置的,外部无法修改的
    
    //executor函数里的内容是同步执行的
    function Promise(executor) {
        //状态值
        this.PromiseState = 'pending';
        //属性值
        this.PromiseResult = null;
    
        //用来保存所有待调用的包含onResolved和onRejected回调函数的对象的数组
        this.callbacks = [];
    
        const self = this;
    
        // function中的this指向window
        function resolve(data) {
            if(self.PromiseState !== 'pending') return;
    
            self.PromiseState = 'fulfilled';
            self.PromiseResult = data;
    
            //异步调用所有待处理的onResolved成功回调函数
            if(self.callbacks.length  0) {
                setTimeout(() = {
                    self.callbacks.forEach(item = {
                        item.onResolved();
                    });
                })
            }
        }
    
        function reject(data) {
            if(self.PromiseState !== 'pending') return;
    
            self.PromiseState = 'fulfilled';
            self.PromiseResult = data;
    
            //异步调用所有待处理的onRejected成功回调函数
            if(self.callbacks.length  0) {
                setTimeout(() = {
                    self.callbacks.forEach(item = {
                        item.onRejected();
                    });
                })
            }
        }
    
        try {
            //同步调用执行器函数
            executor(resolve, reject);
        }catch(e) {
            reject(e);  //异常则直接失败
        }
    }
    
    
    Promise.prototype.then = function(onResolved, onRejected) {
        const self = this;
    
        // 处理异常穿透 
        //当出现异常或者rejected时,虽然then中没有处理rejected的函数,但如果有catch函数,则会一直穿透,交给catch去处理
        if(typeof onRejected !== 'function') {
            onRejected = reason = {
                throw reason;
            }
        }
    
        if(typeof onResolved !== 'function') {
            onResolved = value = value;
        }
        return new Promise((resolve, reject) = {
            function callback(type) {
                try {
                    let result = type(self.PromiseResult);
    
                    if(result instanceof Promise) {
                        // 返回一个新的promise
                        result.then(v = {
                            resolve(v);
                        }, r = {
                            reject(r);
                        })
                    }else {
                        resolve(result);
                    }
                }catch(e) {
                    reject(e);
                }
            }
            if(this.PromiseState === 'fulfilled') {
                setTimeout(() = {
                    callback(onResolved);
                })
            }
        
            if(this.PromiseState === 'rejected') {
                setTimeout(() = {
                    callback(onRejected);
                })
            }
        
            if(this.PromiseState === 'pending') {
                //将onResolved和onRejected保存起来
                this.callbacks.push({
                    onResolved: function() {
                        callback(onResolved);
                    },
                    onRejected: function() {
                        callback(onRejected);
                    } 
                })
            }
        })
    }
    
    Promise.prototype.catch = function(onRejected) {
        return this.then(undefined, onRejected);
    }
    
    //返回一个成功的 promise 对象 
    Promise.resolve = function(value) {
        return new Promise((resolve, reject) = {
            if(value instanceof Promise) {
                value.then(v = {
                    resolve(v);
                }, r = {
                    reject(r);
                })
            }else {
                resolve(value);
            }
        })
    }
    
    //返回一个失败的 promise 对象
    Promise.reject = function(reason) {
        return new Promise((resolve, reject) = {
            reject(reason);
        })
    }
    
    // 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败 
    Promise.all = function(promises) {
        return new Promise((resolve, reject) = {
            let count = 0;
            let arr = [];
    
            for(let i=0; ipromises.length; i++) {
                promises[i].then(v = {
                    count++;
                    arr[i] = v;
    
                    //只有所有promise都成功,才返回成功
                    if(count === promises.length) {
                        resolve(arr);
                    }
                }, r = {
                    // 只要有一个失败,就返回失败
                    reject(r);
                })
            }
        })
    }
    
    // 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态 
    Promise.race = function(promises) {
        return new Promise((resolve, reject) = {
            for(let i=0; ipromises.length; i++) {
                promises[i].then(v = {
                    resolve(v);
                }, r = {
                    reject(r);
                })
            }
        })
    }
    

promise的自定义代码实现 相关文章

  1. C++ 编译时字符串加密

    C++源代码虽然被反编译不太可能,但写在源代码里的常量字符串却在有些情况下会泄漏一些重要信息。比如 sql语句、数据库连接字符串、密码、密钥等等。 用户通过PEEdit之类的软件不但可以看到,还可以修改以后将文件别存为一个新的PE文件,并且程序也会按照修

  2. .net5 core webapi进阶之四:自定义中间件的使用

    一、什么是中间件先看看微软官方文档对中间件的定义: 官网地址:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/view=aspnetcore-5.0 官网还给出了一张中间件调用的示意图,如下: 简而言之,我们可以把中间件理解成一个功能,它可

  3. C++算法代码——小C的数学广角

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.phpid=1659、 题目描述 当小C 4年级的时候,他的数学书上有一个数学广角记载着这样一道题:有n个人(n=100)在水龙头前拿着水桶排队准备装水,每个人装水所需时间不同。为了使大家等待的时间总和尽量

  4. C++算法代码——判断回文

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.phpid=1026 题目描述 输入一串字符,字符个数不超过100,且以.结束,判断它们是否构成回文。 输入 一串字符,以.表示结束。 输出 输出判断的结果,以yes或者no表示。 样例输入 abccba.df 样例输出 yes

  5. go面试题

    第一题: 1、下面这段代码输出的内容 package main import ( "fmt" ) func main() { defer_call() }func defer_call() { defer func() { fmt.Println("打印前") }() defer func() { fmt.Println("打印中") }() defer func() { fmt.Println("打印后") }() pan

  6. servlet提取冗余代码,通过反射完成方法分配,

    package com.zky.hotelmanagement.web.servlet; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.poi.hssf.usermodel.*; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.htt

  7. SeaCms6.4.5 远程代码执行漏洞复现

    SeaCms6.4.5存在远程代码执行漏洞。 注:工具地址 更新4.2版本 链接:https://pan.baidu.com/s/1j-dMtJYiOk2Pfo7QoEXHMA 提取码:rw8l https://wws.lanzous.com/b01zycnta 密码:g3uz 开发手册地址:https://www.kancloud.cn/qq496672097/limanmanexp 漏洞点

  8. VUE学习笔记(四)

    1. 组件化和模块化的区别: - 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一; - 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用; 2. 创建组件的方式 方式一: // 1.1 使用Vue.extend创建

  9. JAVA基础01注释

    JAVA基础01注释 平时写代码可以看懂自己写的,如果项目结构多起来,或者是团队开发,后期维护的时候,我们需要用到注释。 注释不会被执行,注释是给人看的。 写注释是一个很好的习惯! 但是:平时写代码一定要注意规范! Java的注释的种类 单行注释 多行注释

  10. 每月产品新鲜事|云服务器定价中心改版轻量即将支持自定义镜像

    「产品新鲜事」 告诉你腾讯云服务器每月 产品动态 与 优惠活动 下个月的事,咱们下个月再聊 祝大家三月快乐! 推荐阅读 一月|云服务器上线新地域,轻量支持自动化助手

每天更新java,php,javaScript,go,python,nodejs,vue,android,mysql等相关技术教程,教程由网友分享而来,欢迎大家分享IT技术教程到本站,帮助自己同时也帮助他人!

Copyright 2020, All Rights Reserved. Powered by 跳墙网(www.tqwba.com)|网站地图|关键词