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:

看起来像一个简单的函数,其某些属性初始化为0null 。 这里有一些注意事项:

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函数。 回调再次调用resolvereject

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回调。 这些参数包含有关如何调用resolvereject逻辑。 您可以在上面的doResolve函数中检查resolveCallbackrejectCallback

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函数具有onFulfilledonRejected参数 稍后,它将使用此承诺以价值/理由来解决或拒绝。

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的promise

  • If _state = 0(pending) and promise state has been deferred until another nested promise is resolved, its callback is stored in self._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 or onRejected is null or if we used an empty .then() resolved or reject will be called respectively

    如果onFulfilledonRejectednull或如果我们使用一个空.then() 解析拒绝将分别被调用

  • If cb is not empty then it is calling another function tryCallOne(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() and onRejected() 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() nor onRejected() 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 the finale 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: '))
  1. Promise constructor is called and an instance is created with new Promise

    调用Promise constructor ,并使用new Promise创建实例

  2. executor function is passed to doResolve(executor, this) and callback where we have defined setTimeout will be called by tryCallTwo(executor, resolveCallback, rejectCallback)so it will take 3 seconds to finish

    executor函数传递给doResolve(executor, this)tryCallTwo(executor, resolveCallback, rejectCallback)将调用我们定义了setTimeout回调,因此需要3秒钟才能完成

  3. We are calling .then() over the promise instance so before our timeout is completed or any async api returns, Promise.prototype.then will be called as .then(cb, null)

    我们在promise实例上调用.then() ,因此在timeout或任何异步api返回之前, Promise.prototype.then将被称为Promise.prototype.then .then(cb, null)

  4. .then creates a new promise and passes it as an argument to new Handler(onFulfilled, onRejected, promise)

    .then创建一个新的promise并将其作为参数传递给new Handler(onFulfilled, onRejected, promise)

  5. handle function is called with the original promise instance and the handler instance we created in point 4.

    使用原始promise实例和我们在第4点中创建的handler实例调用handle函数。

  6. Inside the handle function, current self._state = 0 and self._deferredState = 0 so self_deferredState will become 1 and handler instance will be assigned to self.deferreds after that control will return from there

    里面的handle功能,目前self._state = 0self._deferredState = 0这样self_deferredState将成为1handler实例将被分配到self.deferreds后控制将回到那里

  7. 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

  8. 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 call resolve(value).

    当前的promise状态处于挂起状态,它将等待直到解决或拒绝该状态。 因此,在此示例中,在3秒钟后,调用了setTimeout回调,并且我们正在明确解决此问题,这将调用resolve(value)

  9. resolveCallback will be called with value Time is out :) and it will call the main resolve function which will check if value !== null && value == 'object' && value === 'function'

    resolveCallback值将为Time is out :),它将调用主resolve函数,该函数将检查value !== null && value == 'object' && value === 'function'

  10. It will fail in our case since we passed string and self._state will become 1 with self._value = 'Time is out' and later finale(self) is called.

    因为我们通过它会在我们的案例失败stringself._state将成为1self._value = 'Time is out' ,后来finale(self)被调用。

  11. finale will call handle(self, self.deferreds) once because self._deferredState = 1, and for the chain of promises, it will call handle() for each deferred function.

    由于self._deferredState = 1finale将调用一次handle(self, self.deferreds) ,对于诺言链,它将为每个deferred函数调用handle()

  12. In the handle function, since promise is resolved already, it will call handleResolved(self, deferred)

    handle函数中,由于promise已经解决,它将调用handleResolved(self, deferred)

  13. handleResolved function will check if _state === 1 and assign cb = deferred.onFulfilled which is our then callback. Later tryCallOne(cb, self._value) will call that callback and we get the final result. While doing this if any error occurred then promise 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承诺如何从内到外真正发挥作用相关推荐

  1. javascript中对象_了解JavaScript中的承诺

    javascript中对象 我向您承诺,到本文结束时,您将更好地了解JavaScript. 我与JavaScript有一种"爱与恨"的关系. 但是尽管如此,JavaScript一直 ...

  2. javascript模块_JavaScript模块第2部分:模块捆绑

    javascript模块 by Preethi Kasireddy 通过Preethi Kasireddy JavaScript模块第2部分:模块捆绑 (JavaScript Modules Part ...

  3. 如何在10分钟内让Redux发挥作用

    Hi everyone ❤️ 大家好❤️ For a while now I've been hearing my friends and colleagues complaining about h ...

  4. javascript指南_JavaScript还原方法指南

    javascript指南 by Josh Pitzalis 通过乔什·皮茨卡利斯(Josh Pitzalis) JavaScript的Reduce方法的工作原理,使用时间以及它可以完成的一些出色工作 ...

  5. inline内联的用法与作用

    inline内联的用法与作用      内联函数是一种编译机制,优点从代码上是看不出来的,但是程序的执行效率上有差别,通常,编译器对函数调用的处理是一种类似中断的方式,即当执行到函数调用语句时,程序把 ...

  6. 什么是网站内链接及内链优化的好处作用?

    什么是网站内链接     网站内链的名字很多,比如内链,内部链接,网站内链,内链接,网页内链等等,但是意思都是一样的,就是一个网站内部页面的相互超链接.比如,本页面到提高用户体验的这个超链接就是一个内 ...

  7. 为什么游戏AI无法帮助AI在现实世界中发挥作用,但可以

    多人游戏被视为一个硕果累累的竞技场,可以在其中模拟许多现实世界中的AI应用程序场景(例如自动驾驶汽车,无人驾驶无人机和协作商务),这些场景可能过于昂贵,投机性或冒险性,无法在现实世界中进行全面测试. ...

  8. 游戏ai人工智能_为什么游戏AI无法帮助AI在现实世界中发挥作用,但可以

    游戏ai人工智能 多人游戏被视为一个硕果累累的竞技场,在其中可以模拟许多现实世界中的AI应用程序场景(例如自动驾驶汽车,无人驾驶无人机和协作商务),这些场景可能过于昂贵,投机性或冒险性,无法在现实世界 ...

  9. 大数据如何在商业银行战略规划中发挥作用

    大数据如何在商业银行战略规划中发挥作用 摘 要:商业银行战略规划的制定,需要海量数据,但目前,行外数据基本未被纳入银行数据库,行内数据受数据安全等制度约束,使用不足.未来大数据要在商业银行战略领域发挥 ...

最新文章

  1. td里面字体大小怎么改_王者荣耀战区怎么改到其他地方 2020荣耀战区修改方法...
  2. 根据网络状态获取Ip地址
  3. mysql索引 钱缀_【mysql索引】之前缀索引-Go语言中文社区
  4. Py之Xlrd:Xlrd的使用方法总结(获取的sheet名字/sheet索引/sheet内容/数和列数、获取整行和整列的值(列表) 、指定单元格的内容/数据类型)之详细攻略
  5. jquery基础总结
  6. 二级c语言上机编程技巧,二级C语言上机编程题技巧总结
  7. 通过Windows Azure Connect ,实现本地机器与Windows Azure 虚拟机的相互连接(转+译)...
  8. ITK:提取具有多个分量的图像通道
  9. adb 命令 pc端 复制粘贴 文本到android设备
  10. 探索SwitchYard 2.0.0.Alpha2快速入门
  11. Android一个自定义的进度环:ProgressChart
  12. 【转】2.2【MySQL】运行原理(二):InnoDB 内存结构、磁盘结构及update sql执行过程分析
  13. c# 审批流引擎_小熊OA:流程引擎才能真正起到管理价值!
  14. 论文翻译:《Improved Neural Relation Detection for Knowledge Base Question Answering》
  15. 2016网易有道内推笔试题
  16. 到底有多二 (15 分)
  17. 【转】测试用例编写(功能测试框架)
  18. ant-design tree 设置默认选中状态_[路由系列]5分钟设置一台Ubiquiti的ERX路由器
  19. 安装惠普M1136打印机一直处于“新设备已连接”状态 解决方法
  20. 记录一下idea启动显示If you already have a 64-bit JDK installed ,defined a JAVA_HOME...的错误

热门文章

  1. UNIX网络编程笔记(2):一个简单的时间获取程序
  2. Codeforces 773D Perishable Roads 最短路 (看题解)
  3. 给定有权无向图的邻接矩阵如下,求其最小生成树的总权重,代码。
  4. merge intervals(合并间隔)
  5. 踩坑 net core
  6. [Linux]几个armhf的ubuntu源
  7. AutoMapperHelper
  8. 文档容器iOS网络编程-iCloud文档存储编程实例
  9. [EmguCV|C#]使用CvInvoke自己繪製色彩直方圖-直方圖(Hitsogram)系列(4)
  10. 关于Oracle实时数据库的优化思路