- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想了解以下使用JavaScript promise 的代码段的执行顺序。
Promise.resolve('A')
.then(function(a){console.log(2, a); return 'B';})
.then(function(a){
Promise.resolve('C')
.then(function(a){console.log(7, a);})
.then(function(a){console.log(8, a);});
console.log(3, a);
return a;})
.then(function(a){
Promise.resolve('D')
.then(function(a){console.log(9, a);})
.then(function(a){console.log(10, a);});
console.log(4, a);})
.then(function(a){
console.log(5, a);});
console.log(1);
setTimeout(function(){console.log(6)},0);
结果是:
1
2 "A"
3 "B"
7 "C"
4 "B"
8 undefined
9 "D"
5 undefined
10 undefined
6
我很好奇执行顺序1 2 3 7 ...而不是值
"A"
,
"B"
...
then
函数将被放入浏览器事件队列中。所以我的期望是1 2 3 4 ...
最佳答案
评论
首先,在.then()
处理程序中运行promise,而不从.then()
回调中返回那些 promise ,会创建一个全新的未附加 promise 序列,该序列不会以任何方式与父 promise 同步。通常,这是一个错误,实际上,某些 promise 引擎实际上会在您执行此操作时发出警告,因为这几乎绝不是所希望的行为。唯一想做的就是,当您执行某种类型的“开火”而忘记操作时,您不在乎错误,也不在乎与世界其他地方的同步。
因此,您在Promise.resolve()
处理程序中的所有.then()
Promise都会创建独立于父链运行的新Promise链。您没有确定的行为。这有点像并行启动四个ajax调用。您不知道哪个会先完成。现在,由于这些Promise.resolve()
处理程序中的所有代码都恰好是同步的(因为这不是真实世界的代码),因此您可能会得到一致的行为,但这不是Promise的设计重点,因此我不会花费太多时间试图找出仅运行同步代码的Promise链将首先完成。在现实世界中,这无关紧要,因为如果顺序很重要,那么您就不会有这种机会。
摘要
.then()
处理程序。即使对于同步解决的 promise (例如Promise.resolve().then(...)
)也是如此。这样做是为了保持编程的一致性,因此无论是否立即解决 promise ,始终都会异步调用.then()
处理程序。这样可以防止出现一些计时错误,并使调用代码更容易看到一致的异步执行。 setTimeout()
与计划的.then()
处理程序的相对顺序(如果两者都已排队并且可以运行)。在您的实现中,待处理的.then()
处理程序总是在待处理的setTimeout()
之前运行,但是Promises/A +规范说明并不确定。它说.then()
处理程序可以通过多种方式进行调度,其中某些方法将在未决setTimeout()
调用之前运行,而某些可能在未决setTimeout()
调用之后运行。例如,Promises/A +规范允许使用在待处理的.then()
调用之前运行的setImmediate()
或在待处理的setTimeout()
调用之后运行的setTimeout()
来调度setTimeout()
处理程序。因此,您的代码完全不应该依赖于该顺序。 .then()
处理程序中创建未从处理程序返回的独立 promise 链。这通常是一个错误,除非在极少数情况下会发生火灾,并且在没有错误处理的情况下忘记了。 1 Promise.resolve('A').then(function (a) {
2 console.log(2, a);
3 return 'B';
4 }).then(function (a) {
5 Promise.resolve('C').then(function (a) {
6 console.log(7, a);
7 }).then(function (a) {
8 console.log(8, a);
9 });
10 console.log(3, a);
11 return a;
12 }).then(function (a) {
13 Promise.resolve('D').then(function (a) {
14 console.log(9, a);
15 }).then(function (a) {
16 console.log(10, a);
17 });
18 console.log(4, a);
19 }).then(function (a) {
20 console.log(5, a);
21 });
22
23 console.log(1);
24
25 setTimeout(function () {
26 console.log(6)
27 }, 0);
.then()
处理程序。由于
Promise.resolve()
立即解决,因此Promise库将安排第一个
.then()
处理程序在此Javascript线程完成后运行。在Promises/A +兼容的Promise库中,在当前执行线程完成后以及JS返回事件循环后,将异步调用所有
.then()
处理程序。这意味着该线程中的任何其他同步代码(例如
console.log(1)
)将在接下来运行,这就是您所看到的。
.then()
处理程序(
第4、12、19行)都在第一个处理程序之后链接,并且仅在第一个处理程序轮到之后运行。他们基本上在这一点上排队。
setTimeout()
也在此初始执行线程中,因此它会运行并因此安排了计时器。
setTimeout(fn, 0)
或
.then()
处理程序,它们都计划在此执行线程之后立即运行。
.then()
处理程序被视为“微任务”,因此它们在
setTimeout()
之前首先运行并不奇怪。但是,如果需要特定的命令,则应编写保证命令的代码,而不要依赖于此实现细节。
.then()
处理程序运行。因此,您会看到该
2 "A"
的输出
console.log(2, a)
。
.then()
处理程序返回了纯值,因此该 promise 被视为已解决,因此在
第4行上定义的
.then()
处理程序将运行。在这里,您正在创建另一个独立的Promise链,并介绍通常是错误的行为。
.then()
处理程序在当前执行线程完成后运行。当前执行线程中的是第10行上的
console.log(3, a)
,所以这就是为什么您接下来要看到的原因。然后,该执行线程完成,然后返回到调度程序以查看下一步要运行什么。
.then()
处理程序等待下一次运行。我们刚刚在第5行安排了一个,在第12行的更高级别的链中安排了下一个。如果您在
的第5行上做到了:
return Promise.resolve.then(...)
.then()
处理程序。老实说,我不知道这是按规范,按惯例还是只是一个 promise 引擎与另一个 promise 引擎的实现细节。我想说的是,如果订单对您至关重要,那么您应该通过按特定顺序链接 promise 来强制执行订单,而不要依靠谁赢得了比赛的第一名。
.then()
处理程序,因此您会看到在
的第6行上指定的
7 "C"
。然后,它不返回任何内容,因此该Promise的解析值变为
undefined
。
.then()
处理程序。这再次是该
.then()
处理程序与
第7行上也正在等待运行的处理程序之间的竞赛。我不知道为什么它会在这里选择另一个,只是说它可能不确定或因应 promise 引擎而有所不同,因为代码未指定顺序。无论如何,
第12行中的
.then()
处理程序将开始运行。这又在前一条上创建了一条新的独立或不同步的 promise 链。它会再次调度
.then()
处理程序,然后从该
4 "B"
处理程序中的同步代码中获取
.then()
。所有同步代码都在该处理程序中完成,因此现在,它可以返回到下一个任务的调度程序。
.then()
处理程序,您会得到
8 undefined
。该约定中存在
undefined
,因为该链中的先前
.then()
处理程序未返回任何内容,因此其返回值为
undefined
,因此这是该时刻约定链的已解析值。
1
2 "A"
3 "B"
7 "C"
4 "B"
8 undefined
.then()
处理程序。运行后,您将获得输出
9 "D"
,然后再次返回到调度程序。
Promise.resolve()
链一致,该调度选择运行在
第19行上定义的下一个外部
.then()
处理程序。它运行,您将获得输出
5 undefined
。再次是
undefined
,因为该链中的先前
.then()
处理程序未返回值,因此Promise的解析值为
undefined
。
1
2 "A"
3 "B"
7 "C"
4 "B"
8 undefined
9 "D"
5 undefined
.then()
处理程序,因此它将运行在
第15行上定义的那个处理程序,然后您将获得输出
10 undefined
。
setTimeout()
开始运行,最终输出为:
1
2 "A"
3 "B"
7 "C"
4 "B"
8 undefined
9 "D"
5 undefined
10 undefined
6
.then()
调用相比,待处理的setTimeout()
处理程序如何确定优先级。 .then()
处理程序进行优先级排序。根据此代码的结果,它不是FIFO。 .then()
调用之前优先考虑所有待处理的
setTimeout()
处理程序。您的情况有点奇怪,因为除了指定
.then()
处理程序之外,您没有实际的异步API调用。如果您有任何异步操作实际上在此promise链的开始处花费了任何实时时间,那么您的
setTimeout()
将在真正的异步操作上的
.then()
处理程序之前执行,因为真正的异步操作需要实际的时间来执行。因此,这只是一个人为的示例,而不是实际代码的通常设计案例。
.then()
处理程序的优先级。我不知道该讨论是否在规范中得到解决。我更喜欢以那种程度的细节对我来说无关紧要的方式进行编码。如果我在乎异步操作的顺序,则可以链接我的promise链来控制顺序,并且此实现细节级别不会以任何方式影响我。如果我不在乎顺序,那么我也不在乎顺序,因此实现细节的级别也不会影响我。即使是在某种规范中,似乎您也不应在许多不同的实现(不同的浏览器,不同的Promise引擎)中信任详细信息的类型,除非您在要运行的所有地方都对其进行了测试。因此,当您的 promise 链不同步时,我建议不要依赖特定的执行顺序。
Promise.resolve('A').then(function (a) {
console.log(2, a);
return 'B';
}).then(function (a) {
var p = Promise.resolve('C').then(function (a) {
console.log(7, a);
}).then(function (a) {
console.log(8, a);
});
console.log(3, a);
// return this promise to chain to the parent promise
return p;
}).then(function (a) {
var p = Promise.resolve('D').then(function (a) {
console.log(9, a);
}).then(function (a) {
console.log(10, a);
});
console.log(4, a);
// return this promise to chain to the parent promise
return p;
}).then(function (a) {
console.log(5, a);
});
console.log(1);
setTimeout(function () {
console.log(6)
}, 0);
1
2 "A"
3 "B"
7 "C"
8 undefined
4 undefined
9 "D"
10 undefined
5 undefined
6
setTimeout()
的计时,在您的示例中,这是最后一个在所有未决
.then()
处理程序之后的计时。
2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
....
3.1 Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.
.then()
处理程序必须在调用堆栈返回到平台代码之后异步执行,但是将其完全留给实现方法到底是如何执行,无论是使用
setTimeout()
这样的宏任务还是使用
process.nextTick()
这样的微任务。因此,根据本规范,它不是确定的,不应依赖。
.then()
处理程序与
setTimeout()
相关的时间的信息。这也许并不奇怪,因为
setTimeout()
本身不是ES6规范的一部分(它是主机环境功能,而不是语言功能)。
关于javascript - JavaScript promises中的执行顺序是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36870467/
我有一个 html 格式的表单: 我需要得到 JavaScript在value input 字段执行,但只能通过表单的 submit .原因是页面是一个模板所以我不控制它(不能有
我管理的论坛是托管软件,因此我无法访问源代码,我只能向页面添加 JavaScript 来实现我需要完成的任务。 我正在尝试用超链接替换所有页面上某些文本关键字的第一个实例。我还根据国家/地区代码对这些
我正在使用 JS 打开新页面并将 HTML 代码写入其中,但是当我尝试使用 document.write() 在新页面中编写 JS 时功能不起作用。显然,一旦看到 ,主 JS 就会关闭。用于即将打开的
提问不是为了解决问题,提问是为了更好地理解系统 专家!我知道每当你将 javascript 代码输入 javascript 引擎时,它会立即由 javascript 引擎执行。由于没有看过Engi
我在一个文件夹中有两个 javascript 文件。我想将一个变量的 javascript 文件传递到另一个。我应该使用什么程序? 最佳答案 window.postMessage用于跨文档消息。使
我有一个练习,我需要输入两个输入并检查它们是否都等于一个。 如果是 console.log 正则 console.log false 我试过这样的事情: function isPositive(fir
我正在做一个Web应用程序,计划允许其他网站(客户端)在其页面上嵌入以下javascript: 我的网络应用程序位于 http://example.org 。 我不能假设客户端网站的页面有 JQue
目前我正在使用三个外部 JS 文件。 我喜欢将所有三个 JS 文件合而为一。 尽一切可能。我创建 aio.js 并在 aio.js 中 src="https://code.jquery.com/
我有例如像这样的数组: var myArray = []; var item1 = { start: '08:00', end: '09:30' } var item2 = {
所以我正在制作一个 Chrome 扩展,它使用我制作的一些 TamperMonkey 脚本。我想要一个“主”javascript 文件,您可以在其中包含并执行其他脚本。我很擅长使用以下行将其他 jav
我有 A、B html 和 A、B javascript 文件。 并且,如何将 A JavaScript 中使用的全局变量直接移动到 B JavaScript 中? 示例 JavaScript) va
我需要将以下整个代码放入名为 activate.js 的 JavaScript 中。你能告诉我怎么做吗? var int = new int({ seconds: 30, mark
我已经为我的 .net Web 应用程序创建了母版页 EXAMPLE1.Master。他们的 I 将值存储在 JavaScript 变量中。我想在另一个 JS 文件中检索该变量。 示例1.大师:-
是否有任何库可以用来转换这样的代码: function () { var a = 1; } 像这样的代码: function () { var a = 1; } 在我的浏览器中。因为我在 Gi
我收到语法缺失 ) 错误 $(document).ready(function changeText() { var p = document.getElementById('bidp
我正在制作进度条。它有一个标签。我想调整某个脚本完成的标签。在找到可能的解决方案的一些答案后,我想出了以下脚本。第一个启动并按预期工作。然而,第二个却没有。它出什么问题了?代码如下: HTML:
这里有一个很简单的问题,我简单的头脑无法回答:为什么我在外部库中加载时,下面的匿名和onload函数没有运行?我错过了一些非常非常基本的东西。 Library.js 只有一行:console.log(
我知道 javascript 是一种客户端语言,但如果实际代码中嵌入的 javascript 代码以某种方式与在控制台上运行的代码不同,我会尝试找到答案。让我用一个例子来解释它: 我想创建一个像 Mi
我如何将这个内联 javascript 更改为 Unobtrusive JavaScript? 谢谢! 感谢您的回答,但它不起作用。我的代码是: PHP js文件 document.getElem
我正在寻找将简单的 JavaScript 对象“转储”到动态生成的 JavaScript 源代码中的最优雅的方法。 目的:假设我们有 node.js 服务器生成 HTML。我们在服务器端有一个对象x。
我是一名优秀的程序员,十分优秀!