肿瘤康复网,内容丰富有趣,生活中的好帮手!
肿瘤康复网 > 自己动手写cpu pdf_自己动手写 Promise

自己动手写cpu pdf_自己动手写 Promise

时间:2018-12-30 00:44:19

相关推荐

这段时间在学习Promise,但始终不得要领。为了更好地理解Promise,我决定自己实现一个简易版的Promise,以学习Promise工作原理。该工程名为ToyPromise,仓库地址如下:

/pandengyang/toypromise.git

ToyPromise包含了以下属性和方法:

首先,看一下ToyPromise构造函数,代码如下:

function ToyPromise(resolver, name) { this._status = "pending"; this._name = name; this._fullfilled = function dummyFullfilled(value) { return value; }; this._rejected = function dummyRejected(error) { throw error; }; resolver(this._resolve.bind(this), this._reject.bind(this));}

构造函数先进行了一系列的初始化,包括名称、状态、默认的完成/拒绝回调函数,代码如下:

this._status = "pending"; this._name = name; this._fullfilled = function dummyFullfilled(value) { return value; }; this._rejected = function dummyRejected(error) { throw error; };

默认的完成回调函数将完成值重新返回;默认的拒绝回调函数将拒绝原因重新抛出。

初始化后,构造函数立即执行用户传递的resolver函数,并将_resolve和_reject方法传递给resolver。

resolver(this._resolve.bind(this), this._reject.bind(this));

resolver在决议/拒绝该ToyPromise时会调用该ToyPromise的_resolve/_reject方法。代码如下:

var A = new ToyPromise(function resolver(resolve, reject) { var number = Math.random(); if (number <= 0.5) { resolve("a"); } else { reject(new Error("a")); }}, "A");

_resolve方法中的this指向所属ToyPromise,如果直接将this._resolve作为参数传递给resolver,会发生this绑定丢失。this绑定丢失示例如下:

var name = "window";foo = { name: "foo", bar: function bar() { console.log(this.name); }}; foo.bar(); // foovar bar = foo.bar;bar(); // 输出window,而不是foo,说明this丢失了

为了避免this绑定丢失,我们采用硬绑定的方式来传递_resolve和_reject函数。

resolver会根据执行结果_resolve/_reject这个ToyPromise。_resolve/_reject代码如下:

ToyPromise.prototype._resolve = function resolve(value) { if (this._status != "pending") { return; } this._status = "fullfilled"; this._data = value; setTimeout(this._asyncFullfilled.bind(this), 0);};

ToyPromise.prototype._reject = function reject(error) { if (this._status != "pending") { return; } this._status = "rejected"; this._data = error; setTimeout(this._asyncRejected.bind(this), 0);};

首先,检测该ToyPromise是否决议过,这样可以保证ToyPromise只被决议一次,通过then注册的回调也只会执行一次。代码如下:

if (this._status != "pending") { return; }

然后,利用决议结果填充_status与_data。代码如下:

this._status = "fullfilled"; this._data = value;

this._status = "rejected"; this._data = error;

最后,利用setTimeout异步调用通过then注册的_fullfilled/_rejected回调函数。代码如下:

setTimeout(this._asyncFullfilled.bind(this), 0);

setTimeout(this._asyncRejected.bind(this), 0);

如果不异步调用_fullfilled/_rejected,当在resolver中同步调用_resolve/_reject时,会出现回调函数调用过早的问题。例如:

var A = new ToyPromise(function resolver(resolve, reject) { var number = Math.random(); if (number <= 0.5) { resolve("a"); } else { reject(new Error("a")); }}, "A");A.then(/* callbacks */)

resolver同步调用_resolve/_reject,此时,ToyPromise的构造函数还未返回,A.then也未调用。也就是说,用户还未注册回调函数,回调函数(默认的)就已经运行了。由于ToyPromise只能被决议一次,A.then注册的回调函数永远也不会运行。

现在看一下then方法,then方法用于向ToyPromise注册完成/拒绝回调函数。代码如下:

ToyPromise.prototype.then = function(fullfilled, rejected, name) { this._fullfilled = fullfilled; this._rejected = rejected; nextPromise = new ToyPromise(function resolver(resolve, reject) {}, name); this._nextPromise = nextPromise; console.log("" + this._name + "'s nextPromise is " + name); return nextPromise;};

首先,为当前ToyPromise注册_fullfilled/_rejected函数,代码如下:

this._fullfilled = fullfilled;this._rejected = rejected;

然后,创建一个新的ToyPromise,并让当前ToyPromise指向这个新的ToyPromise,然后返回该ToyPromise。代码如下:

nextPromise = new ToyPromise(function resolver(resolve, reject) {}, name); this._nextPromise = nextPromise; console.log("" + this._name + "'s nextPromise is " + name); return nextPromise;

当一个ToyPromise被决议时,除了执行_fullfilled/_rejected方法外,还需要决议由then返回的ToyPromise,以此实现链式调用。因此,当ToyPromise调用then时,使用_nextPromise指向由then返回的ToyPromise。代码如下:

this._nextPromise = nextPromise;

由此,形成了一条ToyPromise链,示意图如下:

图中,A调用then时,会为A注册完成/拒绝处理函数,然后A指向A.then返回的B。B调用then时,会为B注册完成/拒绝处理函数,然后B指向B.then返回的C。从而形成一条ToyPromise链。

当ToyPromise被决议/拒绝时,会调用_resolve/_reject方法,然后异步调用_asyncFullfilled/_asyncRejected方法。_asyncFullfilled/_asyncRejected方法代码如下:

ToyPromise.prototype._asyncFullfilled = function() { console.log("" + this._name + " " + this._status + ": " + this._data); if (!this._nextPromise) { return; } var result; try { console.log("call " + this._name + "'s _fullfiled"); result = this._fullfilled(this._data); } catch (error) { console.log("reject next promise " + this._nextPromise._name + " by exception" ); this._nextPromise._reject(error);return; } if (result instanceof ToyPromise) { result._fullfilled = this._nextPromise._fullfilled; result._rejected = this._nextPromise._rejected; result._nextPromise = this._nextPromise._nextPromise;this._nextPromise = result;console.log("" + this._name + "'s next promise is " + this._nextPromise._name ); console.log("" + result._name + "'s next promise is " + result._nextPromise._name ); } else { console.log("resolve next promise " + this._nextPromise._name); this._nextPromise._resolve(result); }};

ToyPromise.prototype._asyncRejected = function() { console.log("" + this._name + " " + this._status + ": " + this._data); if (!this._nextPromise) { return; } var result; try { console.log("call " + this._name + "'s _rejected"); result = this._rejected(this._data); } catch (error) { console.log("reject next promise " + this._nextPromise._name + "by exception" ); this._nextPromise._reject(error);return; } if (result instanceof ToyPromise) { result._fullfilled = this._nextPromise._fullfilled; result._rejected = this._nextPromise._rejected; result._nextPromise = this._nextPromise._nextPromise;this._nextPromise = result;console.log("" + this._name + "'s next promise is " + this._nextPromise._name ); console.log("" + result._name + "'s next promise is " + result._nextPromise._name ); } else { console.log("resolve next promise " + this._nextPromise._name); this._nextPromise._resolve(result); }};

首先,检测该ToyPromise是否调用过then,调用了then之后,_nextPromise会被赋值。代码如下:

if (!this._nextPromise) { return;}

其次,执行用户注册的_fullfilled/_rejected函数。若执行过程中没有异常,则使用返回值决议_nextPromise;若执行过程中catch到异常,则使用该异常作为拒绝原因拒绝_nextPromise。代码如下:

var result; try { console.log("call " + this._name + "'s _fullfiled"); result = this._fullfilled(this._data); } catch (error) { console.log("reject next promise " + this._nextPromise._name + " by exception" ); this._nextPromise._reject(error);return; } if (result instanceof ToyPromise) { } else { console.log("resolve next promise " + this._nextPromise._name); this._nextPromise._resolve(result); }

try { console.log("call " + this._name + "'s _rejected"); result = this._rejected(this._data); } catch (error) { console.log("reject next promise " + this._nextPromise._name + "by exception" ); this._nextPromise._reject(error);return; } if (result instanceof ToyPromise) { } else { console.log("resolve next promise " + this._nextPromise._name); this._nextPromise._resolve(result); }

从代码中我们可以看出,ToyPromise链是交叉运行,并不是说第一个ToyPromise是fullfilled的,其后跟着的所有ToyPromise都是fullfilled。

若完成/拒绝回调函数返回的是一个ToyPromise,则返回的ToyPromise会替换掉由then返回的ToyPromise。代码如下:

if (result instanceof ToyPromise) { result._fullfilled = this._nextPromise._fullfilled; result._rejected = this._nextPromise._rejected; result._nextPromise = this._nextPromise._nextPromise;this._nextPromise = result;console.log("" + this._name + "'s next promise is " + this._nextPromise._name ); console.log("" + result._name + "'s next promise is " + result._nextPromise._name ); }

完成/拒绝回调函数返回ToyPromise的示意图如下:

最初,A.then返回了B,A的_nextPromise指向B。若A的_fullfilled返回了B_1,则将A的_nextPromise修正为B_1,B_1的_fullfilled、_rejected、_nextPromise分别指向B的同名字段。当B_1被决议时,会重新触发ToyPromise链的运行。

ToyPromise仅仅用于演示Promise的基本工作原理,没有考虑封装以及Promise的一些偏高级的用法。

如果觉得《自己动手写cpu pdf_自己动手写 Promise》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。