js 关于setTimeout和Promise执行顺序问题

异步 -- Promise和setTimeout 执行顺序

 

Promise 和 setTimeout 到底谁先执行

Chrome开发工程师一篇文章
浏览器异步和单线程的问题

定时器的介绍

1.首先js是单线程,单线程的解释'单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须'
'处理好,后面的才会执行。' 2.setTimeout 是JavaScript 是运行于单线程的环境中的,是计划代码在未来的某个时间执行
'setTimeout'的作用是在间隔一定的时间后,将回调函数插入消息队列中,等栈中的同步任务都执行完毕后,再执
行。因为栈中的同步任务也会耗时,所以间隔的时间一般会大于等于指定的时间。
'setTimeout(fn, 0)'的意思是,将回调函数fn立刻插入消息队列,等待执行,而不是立即执行 3.执行时机是不能保证的,因为在页面的生命周期中, 不同时间可能有其他代码在控制 JavaScript 进程 4.在页面下载完后的'代码运行'、'事件处理程序'、'Ajax 回调函数'都必须使用同样的'线程来执行',浏览器负责
'进行排序',指派'某段代码'在'某个时间点'运行的'优先级'。 5.主 JavaScript 执行进程外,还有一个需要在进程下一次空闲时执行的代码队列。随着页面在其
生命周期中的推移,代码会按照执行顺序添加入队列。
5.1.例如,当某个按钮被按下时,它的事件处理程序代码就会被添加到队列中,并在下一个可能的时间里
执行。当接收到某个' Ajax 响应时','回调函数'的代码会被'添加到队列'。在 JavaScript 中没有任何代
码是立刻执行的,但一旦进程空闲则尽快执行。 6.定时器的工作机制也是类似:'当特定时间过去后'将'代码插入'。注意,给队列添加代码并'不意味着对 它立刻执行',
而只能'表示它会尽快执行'。设定一个 150ms 后执行的定时器不代表到了 150ms 代码就立刻 执行,它表示代码
'会在 150ms 后被加入到队列中'
7.如果在这个时间点上,队列中没有其他东西,那么这 段代码就会被执行,表面上看上去好像代码就在精确指定
的时间点上执行了。其他情况下,'代码可能明显地等待更长时间才执行。'
JavaScript高级程序设计(第3版)中的一个案例来说明定时器会延迟执行
1.下面代码有一个点击事件,当点击事件结束触发,会触发里面的定时器,那么定时器真的会在事件触发的250ms
后执行么?
答案:尽管在 255ms 处添加了定时器代码,但这时候还不能执行,因为 onclick 事件处 理程序仍在运行。
定时器代码最早能执行的时机是在 300ms 处,即 onclick 事件处理程序结束之后。

var btn = document.getElementById("my-btn");
btn.onclick = function(){
setTimeout(function(){
document.getElementById("message").style.visibility = "visible";
}, 250);
//其他代码
};
小技巧连续的定时器
1.setInterval() 是连续执行的定时器,这个会有一个弊端像下面图一样:
定时器是在 205ms 处添加到队列中的,但是直到过了 300ms 处才能够执行第一个定时器。当执行
这个定时器代码时,在 405ms 处又给队列添加了另外一个副本。在下一个间隔,即 605ms 处,第一
个定时器代码仍在运行,同时在队列中已经有了一个定时器代码的实例。结果是,在这个时间点上的
定时器代码不会被添加到队列中。结果在 5ms 处添加的定时器代码结束之后,405ms 处添加的定时器代码
就立刻执行。

  • 使用链式setTimeout() 解决
1.每次函数执行的时候都会创建一个新的定时器。第二个 setTimeout()调用使用了 arguments.callee 来获取对
当前执行的函数的引用,并为其设置另外一 个定时器。这样做的好处是,在前一个定时器代码执行完之前,
不会向队列插入新的定时器代码,确保 不会有任何缺失的间隔
setTimeout(function(){
//处理中
setTimeout(arguments.callee, interval);
}, interval);
  • 书中一个元素向右移动,当左坐标在 200 像素的时候停止的案例
setTimeout(function(){
var div = document.getElementById("myDiv");
left = parseInt(div.style.left) + 5;
div.style.left = left + "px";
if (left < 200){
setTimeout(arguments.callee, 50);
}
}, 50);

Promise 和 setTimeout 的执行顺序

1.Promise 和 setTimeout 都是异步,都会被在特定时间添加到队列中,那么到底谁会先执行?
2.首先要弄清'任务'和'微观任务',在'setTimeout'章节已经可以知道因为'js是单线程的缘故'所以
他需要对执行'任务'进行类似队列来决定他们的执行顺序触发时机,在任务中还有一种任务叫
'微观任务(Microtasks)'
一个说明的案例
1.下面代码打印结果为'a,b,c,d',先打印'a'在打印'b' 因为代码的先后执行顺序先依次'a' 和'b' 但是'c'
和'd' 都是异步他们的先后执行显而易见不会因为他们代码执行顺序先后而依次打印。
2.首先'Promise ':需要进行 io、等待或者其它异步操作的函数,不返回真实结果,而返回一'承诺',
函数的调用方可以在合适的时机,选择等待这个承诺兑现(通过 Promise 的 then 方法的回调)
3.这里可以简单的理解这两个异步:'Promise 属于我们说的微观任务,setTimeout 属于任务',因此
'Promise 永远在队列尾部添加微观任务。setTimeout 等宿主 API,则会添加任务。'因此可以得到
一个结论'作为微观任务的代表Promise这个异步会直接在特定情况下添加到对应队列执行尾部',
'setTimeout 则会根据调用他的宿主api执行了才把自己放到尾部'
4.因此'Promise 会比setTimeout先执行'
var r = new Promise(function(resolve, reject){
console.log("a");
resolve()
});
setTimeout(()=>console.log("d"), 0)
r.then(() => console.log("c"));
console.log("b")
再来一个极端的案例接着说明
1.我们延迟Promise执行时间,增加到1s,这时候打印结果如果按照我们的猜想,即使'Promise'延迟了
你'setTimeout'也要排在我的后面,因为我'Promise' 就是比你先进队列的不服你也给等着'我微观任务'
就是牛逼因此打印结果'c1 c2 d'
2.根据' 极客时间 winter老师的总结'这里要说明根据谷歌浏览器的开发博客我们可以知道没有'宏观任务的说法'
只有微观任务和任务的说法我这里理解'winter是为了让大家更好的理解将任务比喻成宏观任务':
2.1.首先我们分析有多少个宏任务;
2.2.在每个宏任务中,分析有多少个微任务;根据调用次序,确定宏任务中的微任务执行次序;
2.3.根据宏任务的触发规则和调用次序,确定宏任务的执行次序;
2.4.确定整个顺序。
setTimeout(()=>console.log("d"), 0)
var r = new Promise(function(resolve, reject){
resolve()
});
r.then(() => {
var begin = Date.now();
while(Date.now() - begin < 1000);
console.log("c1")
new Promise(function(resolve, reject){
resolve()
}).then(() => console.log("c2"))
});
  • 一个很有意思的属性'MutationObserver'

js 关于setTimeout和Promise执行顺序问题的更多相关文章

  1. 宏任务和微任务:setTimeout和Promise执行顺序

    先以一道面试题做引子: 写出这段程序的输出内容: setTimeout(function(){ console.log(); },); new Promise(function(a,b){ conso ...

  2. 关于setTimeout和Promise执行顺序问题

    先看一段代码 console.log('打印'+1); setTimeout(function(){ console.log('打印'+2); }) new Promise(function(reso ...

  3. wex5 实战 wex5与js的组件关系与执行顺序(父子与先后)

    初学wex5,先理理让人容易混淆的三个概念: 一 基本概念: 1 wex5组件,顾名思义,在编辑窗口右侧的组件集合里的,都是wex5基于开源自创的组件,并封装了一套自已的方法.目的是为了方便.相关方法 ...

  4. JS的预编译和执行顺序 详析

    原文:JS的预编译和执行顺序 详析 最近在复习javascript的事件处理时发现了一个问题,然后也是我来写javascript的预编译和执行顺序的问题   代码:   复制代码 代码一 <ht ...

  5. JS中For循环中嵌套setTimeout()方法的执行顺序

    在For循环中执行setTimeOut()方法的代码,执行顺序是怎样的呢? 代码如下 function time() { for(var i= 0;i<5;i++){ setTimeout(fu ...

  6. JS的预编译和执行顺序 详析(及全局与局部变量)

    最近在复习javascript的事件处理时发现了一个问题,于是总结一下:javascript的预编译和执行顺序的问题:   <html> <head> <title> ...

  7. JS day01——window对象、执行顺序、线程模型

    1.window对象 window对象表示当前浏览器的窗口,它是一个顶级对象,我们创建的所有对象.函数.变量都是window对象的成员. window对象自带了一些非常有用的方法.属性. window ...

  8. js函数和变量的执行顺序【易错】

    js函数和变量的声明与执行顺序 一.函数执行顺序 1.正常顺序 function f(){ alert(2); } f(); //alert 2 所有浏览器都能测试通过. 2.倒序调用 f(); // ...

  9. 再次聊一聊promise settimeout asycn awiat执行顺序---js执行机制 EVENT LOOP

    首先js是单线程 分为同步和异步,异步又分为(macrotask 宏任务 和 microtask微任务 ), 这图还是很清晰嘛,再来一张 总结一下,就是遇到同步先执行同步,异步的丢到一边依次排队,先排 ...

随机推荐

  1. iOS桌面小插件 Widget Extension

    iOS桌面小插件 Widget Extension 这个插件时iOS14以后才出现的,基于SwiftUI 旧项目新建时可能一堆错误,其中一个时要把插件target 开发sdk版本设置为14.0以上 新 ...

  2. (六)目标检测算法之YOLO

    系列文章链接: (一)目标检测概述 https://www.cnblogs.com/kongweisi/p/10894415.html (二)目标检测算法之R-CNN https://www.cnbl ...

  3. LeetCode-079-单词搜索

    单词搜索 题目描述:给定一个 m x n 二维字符网格 board 和一个字符串单词 word .如果 word 存在于网格中,返回 true :否则,返回 false . 单词必须按照字母顺序,通过 ...

  4. Kubernetes上安装Metrics-Server

    操作场景 metrics-server 可实现 Kubernetes 的 Resource Metrics API(metrics.k8s.io),通过此 API 可以查询 Pod 与 Node 的部 ...

  5. SQL从零到迅速精通【规则和约束】

    1.[创建规则] 为stu_info表定义一个规则,指定其成绩列的值必须大于0,小于100,输入语句如下. USE test_db; GO CREATE RULE rule_score AS @sco ...

  6. MySql 和SQLServer 申明变量以及赋值

    sql server中变量要先申明后赋值: 局部变量用一个@标识,全局变量用两个@(常用的全局变量一般都是已经定义好的): 申明局部变量语法:declare @变量名 数据类型:例如:declare ...

  7. 程序设计基础·Java学习笔记·面向对象(上)

    Java程序设计基础之面向对象(上) (自适应学习进度而进行记录的笔记,希望有一些小小的用处吧(^∀^●)ノシ) (新人上路,望多指教,如有错误,望指正,万分感谢(o゚v゚)ノ) 目录 一.面向对象 ...

  8. JavaWeb——Http

    4.1.什么是http http(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上. 文本:无链接 超文本:利用超链接将普通文本的信息组织在一起的超级文本 4.2.http两个时代的 ...

  9. Spring——自动装配的三种实现方式

    依赖注入的本质是装配,装配是依赖注入的具体行为 spring会在上下文中自动寻找,并自动给bean装配属性 自动装配的三种方式 (1).在xml中显式的装配 (2).在java中显式的装配 (3).隐 ...

  10. Python3输出九九乘法表

    for i in range(1,10): for j in range(1,i+1): print('{}x{}={}\t'.format(i, j, i*j), end='') #format格式 ...