Promiseのthenメソッドをシミュレートするための連鎖呼び出し(第3版、ES5非矢印関数の作成)

/* t05.js */
// 模拟Promise 的then 方法的链式调用(第三版,ES5 非箭头函数写法)
// 本程序只模拟Promise 链式调用以理解使用其API,对异步函数的顺序执行不做模拟。

/*
有两点需要注意的:
1、在定义的时候将一些变量注入给回调函数;
2、在回调函数真正运行时可通过形参获取之前注入的变量。
*/

// 用构造函数定义个类PP 模拟Promise 类
function PP(id, pending) {
    // 多增加一个id 属性,以区分是哪个PP 实例
    this.id = id;
    // Promise 有三种状态:pending、resolved、rejected
    this.state = 'pending'; // 初始化状态为pending

    // 用bind 方法返回的绑定了PP 类的实例化对象的新函数注入给回调函数pending
    pending(PP.resolve.bind(this), PP.reject.bind(this));
    // 使用本构造函数实例化时,回调函数可以通过形参获取以上两个方法
}

// 定义类PP 的静态方法resolve 和reject
// reject 方法主要作用就是改变本对象的state 为rejected,错误信息原封不动保存下来
PP.reject = function(error) {
    console.log(this.id, '1st Error: ' + error);
    this.error = error; // 保存错误信息
    this.state = 'rejected'; // 改变本对象的状态为rejected
};
// resolve 方法主要作用就是改变本对象的state 为resolved,数据信息原封不动保存下来
PP.resolve = function(value) {
    console.log(this.id, '1st Value: ' + value);
    this.value = value; // 保存返回数据
    this.state = 'resolved'; // 改变本对象的状态为resolved
};

// 哪个PP 对象调用then,方法里的this 就指向谁,所以将其定义在原型对象中避免每个实例都有相同的定义代码
PP.prototype.then = function(resolve, reject) {
    console.log('ID', this.id, 'STATE', this.state);
    if (this.state == 'rejected') {
        // 将本对象的error 即new PP 时保存原封不动的错误信息注入到reject 方法中,调用时可通过形参获取
        reject(this.error);
        // 默认return undefined,由于报错不返回PP 对象,后续的.then 都不能执行
    } else {
        // 将本对象的value 即new PP 时保存原封不动的数据注入到resolve 方法中,调用时可通过形参获取
        let result = resolve(this.value);
        // 判断resolve 的返回值,如是PP 对象则将其返回,否则将result 保存到本对象的value 中
        if (result instanceof PP) {
            return result;
        } else {
            this.value = result;
            return this;
        }
    }
};


// ---------------------------------------------------------------------------
// 自定义函数,模拟会有可能产生错误的函数
// 第一个参数是错误标识,非0 表有错误
// 第二个参数是返回数据,这里简单点,给它设置什么就返回什么
// 第三个参数是回调函数,在下面调用时,有错误就调用PP 对象的reject 方法
function getData(eflag, data, callback) {
    callback(eflag, data);
}

// 调用测试:创建PP 实例对象p1,回调函数中调用getData 函数
// 形参resolve 和reject 就对应定义PP 时注入的resolve_fn 和reject_fn
// 跟Promise 对象一样,new 的时候就会执行回调函数
var p1 = new PP(101, function(resolve, reject) {
    // 设置getData 第一个参数非0 即表示有错误产生
    getData(0, 'WAHAHA', function(err, data) {
        console.log('getData ', ' | err:', err, ' | data:', data);
        if (err != 0) { // 如果有错误发生则调用本对象的reject 方法
            reject(err);
        } else {
            resolve(data); // 如果一切正常则调用本对象的resolve 方法
        }
    })
});


p1 // PP 类原型的then 方法
// 第一个回调函数会设置成PP 对象的resolve 方法,即初始化的resolve 方法会被覆盖
// 第二个回调函数会设置成PP 对象的reject 方法,可省略第二个参数
    .then(
        function(value) {
            console.log('Value: ', value);
            return 110;
        })
    .then(
        function(value) {
            console.log('Value: ', value);
            // 返回一个新的PP 对象,下一次调用的是该对象的then 方法
            return new PP(202, function(resolve, reject) {
                // 设置getData 第一个参数非0 即表示有错误产生
                getData(99, 'NEWPP', function(err, data) {
                    console.log('getData ', ' |err:', err, ' |data:', data);
                    if (err != 0) { // 如果有错误发生则调用本对象的reject 方法
                        reject(err);
                    } else {
                        resolve(data); // 如果一切正常则调用本对象的resolve 方法
                    }
                });
            })
        })
    .then(function(value) {
            console.log('Value: ', value);
        },
        function(error) {
            console.log('Error: ', error);
        });

/*
保存以上JavaScript 为t05.js
    
同一目录下新建文件t05.html 内容为:
<script src="t05.js"></script>
    
再在浏览器打开t05.html 即可在开发者工具的Console 里看到效果。
*/

ランニング効果

L @ H ES6 $ノードt05

getData | エラー:0 | データ:WAHAHA

101「1番目の値:WAHAHA」

ID 101 STATEが解決されました

値:WAHAHA

ID 101 STATEが解決されました

値:110

getData | err:99 | data:NEWPP

202「最初のエラー:99」

ID 202 STATEが拒否されました

エラー:99

元の記事27件を公開 賞賛された4件 訪問9695件

おすすめ

転載: blog.csdn.net/yoshubom/article/details/89226147