zoukankan      html  css  js  c++  java
  • 原生js实现Promise(简版+升级版)

    JS 实现 Promise
    ===============

    之前查阅了几篇blog作为参考,最终参考了:https://www.cnblogs.com/hjj2ldq/p/9489598.html
     
     
    github源码地址:https://github.com/ronliruonan/sv-book/tree/master/javascript/promise

    MDN语法的理解
    ------------------ 
    var executor = function(resolve, reject){...}
    
    new Promise(executor);

    - Promise构造函数 接收的一个executor函数

    - executor函数 接收两个参数(resolve, reject):resolve 被作为成功函数来对待使用,reject 被作为失败函数来对待使用;
    - resolve函数 被调用时,Promise的状态改为`fulfilled`,reject函数被调用时,Promise状态改为`rejected`

    - Promise 在接收到executor函数时,将会 ```立即执行```executor函数,并且发生在Promise返回promise实例之前被调用
    - executor执行过程中,成功逻辑调用resoleve函数;失败逻辑调用reject函数;如果发生异常,Promise的状态将是`rejected`
    - executor函数的返回值将被忽略。

    MDN描述的理解
    ---------------
    - Promsie 具有3种状态,除了上面提到的`fulfilled`和`rejected`两种,还有一个种:`pending`(初始状态,不代表成功,也不代表失败状态)

    - Promise.prototype.then(onfulfilled, onrejected) 接收两个回调函数;最终返回promise对象,传递了原有的status
    - Promise.prototype.catch() 最终也是返回promise对象
    - 综上,Promise可以被链式调用

    MDN的方法
    -----------
    - Promise.all(iterable)
    - Promise.race(iterable)
    - Promise.reject(reason)
    - Promise.resolve(value) value具有三种类型,需要特殊对待

    MDN的原型 - 方法
    ------------
    - Promise.prototype.catch(onRejcted)
    - Promise.prototype.then(onFulfilled, onRejected)
    - Promise.prototype.finally(onFinally)

    回归主题 js 实现Promise
    ========================
    此次仅实现了
    - Promsie.prototype.constructor
    - Promise.prototype.then(onResolve, onReject)
    - Promise.reject(onReject)
    - Promsie.resolve(value) 未实现value包含`then:function`的特性

    简版实现思维
    ---------
    用到了队列 和 闭包。 代码实现在 [js-promise.html](js-promise.html)
    这个思路受到blog的启发,基于blog的思路,实现了更为贴切原生Promise的功能
    function (executor) {
    this.status = 'pending'; // 默认状态
    this.value = void 0; // 默认值 undefined
    this.keepResolveFn = []; // 成功回调队列
    this.keepRejectFn = []; // 失败回调队列
    
    const resolve = (val) => {
    this.status === 'pending' && (
    this.status = 'fulfilled',
    this.value = val,
    this.keepResolveFn.forEach(fn => fn())
    );
    };
    const reject = (val) => {
    this.status === 'pending' && (
    this.status = 'rejected',
    this.value = val,
    this.keepRejectFn.forEach(fn => fn())
    );
    };
    
    try {
    executor(resolve, reject); // Promise 内部立即执行executor函数
    } catch (error) {
    reject(error);
    }
    }
    
    FnPromise.prototype.then = function (onResolve, onReject) {
    this.status === 'fulfilled' && onResolve(this.value);
    this.status === 'rejected' && onReject(this.value);
    
    // 这一步pending状态的方案,真的佩服参考blog的作者,茅塞顿开
    this.status === 'pending' && (
    this.keepResolveFn.push(() => onResolve(this.value)),
    this.keepRejectFn.push(() => onReject(this.value))
    );
    
    return this; // 自动传递了Promise的状态
    }

    验证 简版
    -------------
    通过与原生Promise的使用对比,直接resolve
    ```
    /* 最简单的成功回调 */
    var p1 = new Promise(resolve => resolve(200));
    p1
    .then(res => console.log('p1 最简单的成功回调: ', res))
    /* Promise.then()返回promise对象,并保留resolve状态 */
    .then(a => console.log('p1 必须出现'), b => console.log('p1 不会出现'));
    
    
    /* 最简单的成功回调 */
    var fp1 = new Promise(resolve => resolve(200));
    fp1
    .then(res => console.log('fp1 最简单的成功回调: ', res))
    /* Promise.then()返回promise对象,并保留resolve状态 */
    .then(a => console.log('fp1 必须出现'), b => console.log('fp1 不会出现'));
    ```
    通过与原生Promise的使用对比,使用setTimeout() 异步 resolve
    ```
    /* 异步回调 */
    var sync_p = new Promise(resolve => setTimeout(resolve, Math.random() * 4000, 304));
    sync_p
    .then(res => console.log('sync_p 异步回调: ', res))
    /* 异步回调的.then() 返回同样状态的promise */
    .then(a => console.log('sync_p 必须成功'), b => console.log('sync_p 不可能出现'));
    
    /* 异步回调 */
    var sync_fp = new Promise(resolve => setTimeout(resolve, Math.random() * 5000, 304));
    sync_fp
    .then(res => console.log('sync_fp 异步回调: ', res))
    /* 异步回调的.then() 返回同样状态的promise */
    .then(a => console.log('sync_fp 必须成功'), b => console.log('sync_fp 不可能出现'));
    ```

    升级版本疑问
    -----------------
    简版Promise 无法实现一下原生效果。

    `一大难点:异步Promise后.then()中直接return 新的异步Promise后,下一次.then()的所属为上一步的新异步Promise`
    ```
    var b = 10;
    var p1 = new Promise(resolve => {
    setTimeout(() => {
    console.log(' b += 10');
    b += 10;
    resolve();
    }, 1000 * 10);
    });
    
    p1
    .then(() => {
    console.log(' 第一次输出应该是20: ', b);
    
    return 2;
    })
    .then((res) => {
    console.log(' 第二次输出应该是20: ', b);
    console.log('res is 2: ', res);
    
    return new Promise(resolve => {
    setTimeout(() => {
    console.log(' b *= b')
    b *= b;
    resolve();
    }, 1000 * 2);
    });
    })
    .then(() => {
    console.log(' 第3次输出应该是20*20: ', b);
    return new Promise(resolve => {
    setTimeout(() => {
    console.log(' b = 0')
    b = 0;
    resolve();
    }, 1000 * 2);
    });
    })
    .then(
    () => console.log(' 应该是最后一次输出0: ', b),
    () => console.log(' 不应该出现异常')
    );
    ```

    升级版思维
    -------------
    沿用简版的队列、闭包思维,增加了递归(用来修订队列中的FnPromise的执行关系)

    代码实现在 [js-promise-plug.html](js-promise-plus.html)

    已经亲自验证了 升级版的疑问效果。

    ps:
    思考方案 -> blog论证 -> 简版(coding、代码验证、逻辑推敲、代码验证、逻辑推敲) -> 升级版(coding、代码验证、逻辑推敲、代码验证、逻辑推敲...) -> 脑仁疼了2、3天
  • 相关阅读:
    编写 iPhone Friendly 的 Web 应用程序
    WebService的安全性讨论【身份识别】
    使用InstallShield系统变量的缺省值
    数据库用户操作相关
    TFS2010安装
    微软实验虚拟机下载地址
    生成18位不重复的ID
    Linux 账户 帐户管理 文件权限 权限管理
    Chrome 插件开发
    Ubuntu 环境变量 设置
  • 原文地址:https://www.cnblogs.com/Ruonan-Li/p/11072136.html
Copyright © 2011-2022 走看看