javascript 作用_JavaScript承诺如何从内到外真正发挥作用
javascript 作用
One of the most important questions I faced in interviews was how promises are implemented. Since async/await is becoming more popular, you need to understand promises.
我在采访中面临的最重要的问题之一是如何实现承诺。 由于异步/等待变得越来越流行,因此您需要了解Promise。
什么是诺言? (What is a Promise?)
A promise is an object which represents the result of an asynchronous operation which is either resolved or rejected (with a reason).
一个promise是一个对象,它表示异步操作的结果,该结果被解决或被拒绝(有原因)。
There are 3 states
有3个州
Fulfilled:
onFulfilled()
will be called (e.g.,resolve()
was called)已实现:将调用
onFulfilled()
(例如,调用了resolve()
)Rejected:
onRejected()
will be called (e.g.,reject()
was called)拒绝:将调用
onRejected()
(例如,调用了reject()
)Pending: not yet fulfilled or rejected
待处理:尚未实现或拒绝
So let’s see how’s it is implemented:
因此,让我们看看它是如何实现的:
https://github.com/then/promise/blob/master/src/core.js
https://github.com/then/promise/blob/master/src/core.js
According to the definition at Mozilla: It takes an executor function as an argument.
根据Mozilla的定义:它以执行程序函数作为参数。
function noop() {} function Promise(executor) {if (typeof this !== 'object') {throw new TypeError('Promises must be constructed via new');}if (typeof executor !== 'function') {throw new TypeError('Promise constructor\'s argument is not a function');}this._deferredState = 0;this._state = 0;this._value = null;this._deferreds = null;if (executor === noop) return;doResolve(executor, this);
}
Looks like a simple function with some properties initialized to 0
or null
. Here are a few things to notice:
看起来像一个简单的函数,其某些属性初始化为0
或null
。 这里有一些注意事项:
this._state
property can have three possible values as described above:
this._state
属性可以具有三个如上所述的可能值:
0 - pending1 - fulfilled with _value2 - rejected with _value3 - adopted the state of another promise, _value
Its value is0
(pending) when you create a new promise.
创建新的承诺时,其值为0
( 待定) 。
Later doResolve(executor, this)
is invoked with executor and promise
object.
之后, doResolve(executor, this)
与executor and promise
对象一起调用。
Let’s move on to the definition of doResolve
and see how it’s implemented.
让我们继续进行doResolve
的定义,看看它是如何实现的。
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/function doResolve(fn, promise) {var done = false;var resolveCallback = function(value) {if (done) return;done = true;resolve(promise, value);};var rejectCallback = function(reason) {if (done) return;done = true;reject(promise, reason);
};var res = tryCallTwo(fn, resolveCallback, rejectCallback);if (!done && res === IS_ERROR) {done = true;reject(promise, LAST_ERROR);}
}
Here it is again calling tryCallTwo
function with executor and 2 callbacks. The callbacks are again calling resolve
and reject
在这里,它再次使用executor和2个回调调用tryCallTwo
函数。 回调再次调用resolve
和reject
The done
variable is used here to make sure the promise is resolved or rejected only once, so if you try to reject or resolve a promise more than once then it will return because done = true
.
这里, done
变量用于确保仅对诺言进行一次解析或拒绝,因此,如果您多次尝试拒绝或解决诺言,则它将返回,因为done = true
。
function tryCallTwo(fn, a, b) {try {fn(a, b);} catch (ex) {LAST_ERROR = ex;return IS_ERROR;}
}
This function indirectly calls the main executor
callback with 2 arguments. These arguments contain logic on how resolve
or reject
should be called. You can check resolveCallback and rejectCallback in doResolve
function above.
此函数使用2个参数间接调用主executor
回调。 这些参数包含有关如何调用resolve
或reject
逻辑。 您可以在上面的doResolve
函数中检查resolveCallback和rejectCallback 。
If there is an error during execution it will store the error in LAST_ERROR
and return the error.
如果执行期间发生错误,它将错误存储在LAST_ERROR
并返回错误。
Before we jump to the resolve
function definition, let’s check out the .then
function first:
在跳转到resolve
函数定义之前,让我们先检查.then
函数:
Promise.prototype.then = function(onFulfilled, onRejected) {if (this.constructor !== Promise) {return safeThen(this, onFulfilled, onRejected);}var res = new Promise(noop);handle(this, new Handler(onFulfilled, onRejected, res));return res;
};function Handler(onFulfilled, onRejected, promise) {this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null;this.onRejected = typeof onRejected === "function" ? onRejected : null;this.promise = promise;
}
So in the above function, then is creating new promise
and assigning it as a property to a new function called Handler
. The Handler
function has arguments onFulfilled and onRejected. Later it will use this promise to resolve or reject with value/reason.
因此,在上述函数中,将创建新的promise
并将其作为属性分配给一个名为Handler
的新函数。 Handler
函数具有onFulfilled和onRejected参数。 稍后,它将使用此承诺以价值/理由来解决或拒绝。
As you can see, the .then
function is calling again another function:
如您所见, .then
函数再次调用另一个函数:
handle(this, new Handler(onFulfilled, onRejected, res));
实现方式: (Implementation:)
function handle(self, deferred) {while (self._state === 3) {self = self._value;}if (Promise._onHandle) {Promise._onHandle(self);}if (self._state === 0) {if (self._deferredState === 0) {self._deferredState = 1;self._deferreds = deferred;return;}if (self._deferredState === 1) {self._deferredState = 2;self._deferreds = [self._deferreds, deferred];return;}self._deferreds.push(deferred);return;}handleResolved(self, deferred);
}
There is a while loop which will keep assigning the resolved promise object to the current promise which is also a promise for
_state === 3
有一个while循环,它将继续将解析的promise对象分配给当前的promise,这也是
_state === 3
的promiseIf
_state = 0(pending)
and promise state has been deferred until another nested promise is resolved, its callback is stored inself._deferreds
如果
_state = 0(pending)
并且承诺状态已推迟到另一个嵌套的承诺被解决,则其回调存储在self._deferreds
function handleResolved(self, deferred) {asap(function() { // asap is external lib used to execute cb immediatelyvar cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;if (cb === null) {if (self._state === 1) {resolve(deferred.promise, self._value);} else {reject(deferred.promise, self._value);}return;}var ret = tryCallOne(cb, self._value);if (ret === IS_ERROR) {reject(deferred.promise, LAST_ERROR);} else {resolve(deferred.promise, ret);}});
}
What's happening:
发生了什么:
If the state is 1
(fulfilled)
then call the resolve else reject如果状态为1
(fulfilled)
则调用解决方法 else 拒绝If
onFulfilled
oronRejected
isnull
or if we used an empty.then()
resolved or reject will be called respectively如果
onFulfilled
或onRejected
为null
或如果我们使用一个空.then()
解析或拒绝将分别被调用If
cb
is not empty then it is calling another functiontryCallOne(cb, self._value)
如果
cb
不为空,则它正在调用另一个函数tryCallOne(cb, self._value)
function tryCallOne(fn, a) {try {return fn(a);} catch (ex) {LAST_ERROR = ex;return IS_ERROR;}
} a) {
tryCallOne
: This function only calls the callback that is passed into the argument self._value
. If there is no error it will resolve the promise, otherwise it will reject it.
tryCallOne
:此函数仅调用传递到参数self._value
的回调。 如果没有错误,它将解决承诺,否则将拒绝它。
Every promise must supply a .then()
method with the following signature:
每个Promise必须提供具有以下签名的.then()
方法:
promise.then(onFulfilled?: Function,onRejected?: Function
) => Promise
Both
onFulfilled()
andonRejected()
are optional.onFulfilled()
和onRejected()
都是可选的。- If the arguments supplied are not functions, they must be ignored.如果提供的参数不是函数,则必须将其忽略。
onFulfilled()
will be called after the promise is fulfilled, with the promise’s value as the first argument.在实现诺言之后,将调用
onFulfilled()
,并将诺言的值作为第一个参数。onRejected()
will be called after the promise is rejected, with the reason for rejection as the first argument.在拒绝承诺后,将调用
onRejected()
并将拒绝的原因作为第一个参数。Neither
onFulfilled()
noronRejected()
may be called more than once.onFulfilled()
和onRejected()
不得被调用一次以上。.then()
may be called many times on the same promise. In other words, a promise can be used to aggregate callbacks..then()
可能在同一诺言中被多次调用。 换句话说,promise可以用于聚集回调。.then()
must return a new promise..then()
必须返回新的诺言。
承诺链 (Promise Chaining)
.then
should return a promise. That's why we can create a chain of promises like this:
.then
应该兑现承诺。 这就是为什么我们可以创建如下这样的承诺链:
Promise
.then(() => Promise.then(() => Promise.then(result => result)
)).catch(err)
兑现诺言 (Resolving a promise)
Let’s see the resolve
function definition that we left earlier before moving on to .then()
:
让我们看一下在继续.then()
之前我们留下的resolve
函数定义:
function resolve(self, newValue) {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedureif (newValue === self) {return reject(self,new TypeError("A promise cannot be resolved with itself."));}if (newValue &&(typeof newValue === "object" || typeof newValue === "function")) {var then = getThen(newValue);if (then === IS_ERROR) {return reject(self, LAST_ERROR);}if (then === self.then && newValue instanceof Promise) {self._state = 3;self._value = newValue;finale(self);return;} else if (typeof then === "function") {doResolve(then.bind(newValue), self);return;}
}self._state = 1;self._value = newValue;finale(self);
}
We check if the result is a promise or not. If it’s a function, then call that function with value using
doResolve()
.我们检查结果是否是一个承诺。 如果它是一个函数,则使用
doResolve()
以值调用该函数。If the result is a promise then it will be pushed to the
deferreds
array. You can find this logic in thefinale
function.如果结果是一个承诺,那么它将被推送到
deferreds
数组。 您可以在finale
功能中找到此逻辑。
拒绝承诺: (Rejecting a promise:)
Promise.prototype['catch'] = function (onRejected) {return this.then(null, onRejected);
};
The above function can be found in ./es6-extensions.js
.
可以在./es6-extensions.js
找到以上功能。
Whenever we reject a promise, the .catch
callback is called which is a sugar coat for then(null, onRejected)
.
每当我们拒绝承诺时, .catch
调用.catch
回调,这是then(null, onRejected)
。
Here is the basic rough diagram that I have created which is a birds-eye view of what's happening inside:
这是我创建的基本示意图,它是内部情况的鸟瞰图:
Let’s see once again how everything is working:
让我们再次看看一切如何进行:
For example, we have this promise:
例如,我们有以下承诺:
new Promise((resolve, reject) => {setTimeout(() => {resolve("Time is out");}, 3000)
})
.then(console.log.bind(null, 'Promise is fulfilled'))
.catch(console.error.bind(null, 'Something bad happened: '))
Promise
constructor
is called and an instance is created withnew Promise
调用Promise
constructor
,并使用new Promise
创建实例executor
function is passed todoResolve(executor, this)
and callback where we have definedsetTimeout
will be called bytryCallTwo(executor, resolveCallback, rejectCallback)
so it will take 3 seconds to finishexecutor
函数传递给doResolve(executor, this)
和tryCallTwo(executor, resolveCallback, rejectCallback)
将调用我们定义了setTimeout
回调,因此需要3秒钟才能完成We are calling
.then()
over the promise instance so before ourtimeout
is completed or any asyncapi
returns,Promise.prototype.then
will be called as.then(cb, null)
我们在promise实例上调用
.then()
,因此在timeout
或任何异步api
返回之前,Promise.prototype.then
将被称为Promise.prototype.then
.then(cb, null)
.then
creates a newpromise
and passes it as an argument tonew Handler(onFulfilled, onRejected, promise)
.then
创建一个新的promise
并将其作为参数传递给new Handler(onFulfilled, onRejected, promise)
handle
function is called with the originalpromise
instance and thehandler
instance we created in point 4.使用原始
promise
实例和我们在第4点中创建的handler
实例调用handle
函数。Inside the
handle
function, currentself._state = 0
andself._deferredState = 0
soself_deferredState
will become1
andhandler
instance will be assigned toself.deferreds
after that control will return from there里面的
handle
功能,目前self._state = 0
和self._deferredState = 0
这样self_deferredState
将成为1
和handler
实例将被分配到self.deferreds
后控制将回到那里After
.then()
we are calling.catch()
which will internally call.then(null, errorCallback)
— again the same steps are repeated from point 4 to point 6 and skip point 7 since we called.catch
once在
.catch()
之后.then()
我们将调用.catch()
,该方法将在内部调用.then(null, errorCallback)
-再次,从点4到点6重复相同的步骤, 并跳过点7,因为我们一次调用.catch
Current
promise
state is pending and it will wait until it is resolved or rejected. So in this example, after 3 seconds,setTimeout
callback is called and we are resolving this explicitly which will callresolve(value)
.当前的
promise
状态处于挂起状态,它将等待直到解决或拒绝该状态。 因此,在此示例中,在3秒钟后,调用了setTimeout
回调,并且我们正在明确解决此问题,这将调用resolve(value)
。resolveCallback
will be called with valueTime is out
:) and it will call the mainresolve
function which will check ifvalue !== null && value == 'object' && value === 'function'
resolveCallback
值将为Time is out
:),它将调用主resolve
函数,该函数将检查value !== null && value == 'object' && value === 'function'
It will fail in our case since we passed
string
andself._state
will become1
withself._value = 'Time is out'
and laterfinale(self)
is called.因为我们通过它会在我们的案例失败
string
和self._state
将成为1
与self._value = 'Time is out'
,后来finale(self)
被调用。finale
will callhandle(self, self.deferreds)
once becauseself._deferredState = 1
, and for the chain of promises, it will callhandle()
for eachdeferred
function.由于
self._deferredState = 1
,finale
将调用一次handle(self, self.deferreds)
,对于诺言链,它将为每个deferred
函数调用handle()
。In the
handle
function, sincepromise
is resolved already, it will callhandleResolved(self, deferred)
在
handle
函数中,由于promise
已经解决,它将调用handleResolved(self, deferred)
handleResolved
function will check if_state === 1
and assigncb = deferred.onFulfilled
which is ourthen
callback. LatertryCallOne(cb, self._value)
will call that callback and we get the final result. While doing this if any error occurred thenpromise
will be rejected.handleResolved
功能会检查是否_state === 1
和分配cb = deferred.onFulfilled
这是我们then
回调。 稍后tryCallOne(cb, self._value)
将调用该回调,然后得到最终结果。 在执行此操作时,如果发生任何错误,则promise
将被拒绝。
当诺言被拒绝时 (When a promise is rejected)
In this case, all the steps will remain the same — but in point 8 we call reject(reason)
. This will indirectly call rejectCallback
defined in doResolve()
and self._state
will become 2
. In the finale
function cb
will be equal to deferred.onRejected
which will be called later by tryCallOne
. That’s how the .catch
callback will be called.
在这种情况下,所有步骤将保持不变-但在第8点中,我们将其称为reject(reason)
。 这将间接调用rejectCallback
doResolve()
定义的doResolve()
而self._state
将变为2
。 在finale
函数中, cb
等于deferred.onRejected
,稍后将由tryCallOne
。 这就是.catch
回调将被调用的方式。
That's all for now! I hope you enjoyed the article and it helps in your next JavaScript interview.
目前为止就这样了! 我希望您喜欢这篇文章,并且对您下一次JavaScript采访有所帮助。
If you encounter any problem feel free to get in touch or comment below. I would be happy to help ?
如果您遇到任何问题,请在 下面 与我们联系 或发表评论。 我很乐意提供帮助吗?
Don’t hesitate to clap if you considered this a worthwhile read!
如果您认为这值得一读,请随时鼓掌!
Originally published at 101node.io on February 05, 2019.
最初于2019年2月5日发布在101node.io上。
翻译自: https://www.freecodecamp.org/news/how-javascript-promises-actually-work-from-the-inside-out-76698bb7210b/
javascript 作用
javascript 作用_JavaScript承诺如何从内到外真正发挥作用相关推荐
- javascript中对象_了解JavaScript中的承诺
javascript中对象 我向您承诺,到本文结束时,您将更好地了解JavaScript. 我与JavaScript有一种"爱与恨"的关系. 但是尽管如此,JavaScript一直 ...
- javascript模块_JavaScript模块第2部分:模块捆绑
javascript模块 by Preethi Kasireddy 通过Preethi Kasireddy JavaScript模块第2部分:模块捆绑 (JavaScript Modules Part ...
- 如何在10分钟内让Redux发挥作用
Hi everyone ❤️ 大家好❤️ For a while now I've been hearing my friends and colleagues complaining about h ...
- javascript指南_JavaScript还原方法指南
javascript指南 by Josh Pitzalis 通过乔什·皮茨卡利斯(Josh Pitzalis) JavaScript的Reduce方法的工作原理,使用时间以及它可以完成的一些出色工作 ...
- inline内联的用法与作用
inline内联的用法与作用 内联函数是一种编译机制,优点从代码上是看不出来的,但是程序的执行效率上有差别,通常,编译器对函数调用的处理是一种类似中断的方式,即当执行到函数调用语句时,程序把 ...
- 什么是网站内链接及内链优化的好处作用?
什么是网站内链接 网站内链的名字很多,比如内链,内部链接,网站内链,内链接,网页内链等等,但是意思都是一样的,就是一个网站内部页面的相互超链接.比如,本页面到提高用户体验的这个超链接就是一个内 ...
- 为什么游戏AI无法帮助AI在现实世界中发挥作用,但可以
多人游戏被视为一个硕果累累的竞技场,可以在其中模拟许多现实世界中的AI应用程序场景(例如自动驾驶汽车,无人驾驶无人机和协作商务),这些场景可能过于昂贵,投机性或冒险性,无法在现实世界中进行全面测试. ...
- 游戏ai人工智能_为什么游戏AI无法帮助AI在现实世界中发挥作用,但可以
游戏ai人工智能 多人游戏被视为一个硕果累累的竞技场,在其中可以模拟许多现实世界中的AI应用程序场景(例如自动驾驶汽车,无人驾驶无人机和协作商务),这些场景可能过于昂贵,投机性或冒险性,无法在现实世界 ...
- 大数据如何在商业银行战略规划中发挥作用
大数据如何在商业银行战略规划中发挥作用 摘 要:商业银行战略规划的制定,需要海量数据,但目前,行外数据基本未被纳入银行数据库,行内数据受数据安全等制度约束,使用不足.未来大数据要在商业银行战略领域发挥 ...
最新文章
- td里面字体大小怎么改_王者荣耀战区怎么改到其他地方 2020荣耀战区修改方法...
- 根据网络状态获取Ip地址
- mysql索引 钱缀_【mysql索引】之前缀索引-Go语言中文社区
- Py之Xlrd:Xlrd的使用方法总结(获取的sheet名字/sheet索引/sheet内容/数和列数、获取整行和整列的值(列表) 、指定单元格的内容/数据类型)之详细攻略
- jquery基础总结
- 二级c语言上机编程技巧,二级C语言上机编程题技巧总结
- 通过Windows Azure Connect ,实现本地机器与Windows Azure 虚拟机的相互连接(转+译)...
- ITK:提取具有多个分量的图像通道
- adb 命令 pc端 复制粘贴 文本到android设备
- 探索SwitchYard 2.0.0.Alpha2快速入门
- Android一个自定义的进度环:ProgressChart
- 【转】2.2【MySQL】运行原理(二):InnoDB 内存结构、磁盘结构及update sql执行过程分析
- c# 审批流引擎_小熊OA:流程引擎才能真正起到管理价值!
- 论文翻译:《Improved Neural Relation Detection for Knowledge Base Question Answering》
- 2016网易有道内推笔试题
- 到底有多二 (15 分)
- 【转】测试用例编写(功能测试框架)
- ant-design tree 设置默认选中状态_[路由系列]5分钟设置一台Ubiquiti的ERX路由器
- 安装惠普M1136打印机一直处于“新设备已连接”状态 解决方法
- 记录一下idea启动显示If you already have a 64-bit JDK installed ,defined a JAVA_HOME...的错误
热门文章
- UNIX网络编程笔记(2):一个简单的时间获取程序
- Codeforces 773D Perishable Roads 最短路 (看题解)
- 给定有权无向图的邻接矩阵如下,求其最小生成树的总权重,代码。
- merge intervals(合并间隔)
- 踩坑 net core
- [Linux]几个armhf的ubuntu源
- AutoMapperHelper
- 文档容器iOS网络编程-iCloud文档存储编程实例
- [EmguCV|C#]使用CvInvoke自己繪製色彩直方圖-直方圖(Hitsogram)系列(4)
- 关于Oracle实时数据库的优化思路