博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
promise,then,setTimeout -- 细致探讨执行流程
阅读量:5876 次
发布时间:2019-06-19

本文共 6669 字,大约阅读时间需要 22 分钟。

本文原理:

JavaScript是单线程,setTimeout会让代码置于线程末尾。

Promise建立后与正常代码一样顺序执行。

Promise在状态变为resolve后才会触发后续的then

  1. 读完本文大约需要15-25分钟
  2. 本文前置知识:基础js,Promise对象,ES6其他基础知识
  3. 阅读难度:初级
  4. 本文所有代码及输出结果都写了出来,可以不用编译器编译,直接浏览文章

如果你知道以下代码的执行结果,那么本文对你的收获就比较有限

const showNode = document.getElementById("show");showNode.innerHTML += "normal | ";let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";  setTimeout(() => { resolve("then |"); }, 0)})promise.then((res) => {  setTimeout(() => { showNode.innerHTML += 'then wait | ' }, 0)  showNode.innerHTML += res;  return " next then | ";}).then((res) => {  showNode.innerHTML += res;  return " next next then | ";}).then((res) => {  showNode.innerHTML += res;})setTimeout(() => { showNode.innerHTML += "wait | " }, 0)// 输出: normal | promise | then | next then | next next then | wait | //       then wait |复制代码

正文开始

Javascript 引擎单线程机制

  • 首先明确,JavaScript引擎是单线程机制

  • JavaScript 是单线程执行的,无法同时执行多段代码。当某一段代码正在执行的时候,所有后续的任务都必须等待,形成一个任务队列。一旦当前任务执行完毕,再从队列中取出下一个任务,这也常被称为 “阻塞式执行”。

  • 可以理解为:只有在 JS线程中没有任何同步代码要执行的前提下才会执行异步代码

有关js线程的知识可以移步

promise,then,setTimeout的执行流程

正常顺序执行 -> then -> setTimeouts -> then中 setTimeouts

注1: showNode 是我用于获取html的元素,直接显示在页面上,替换console.log

注2: 事例代码中,新加的代码或有修改的代码,会在代码后面加上相应的注释

正常执行 :按照正常从上往下的顺序执行

环境1 普通代码在promise之前

showNode.innerHTML += "normal | ";let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";})// 输出: normal | promise |复制代码

环境2 promise在普通代码之前

let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";})  showNode.innerHTML += "normal | ";// 输出: promise | normal |复制代码
  • promise在建立后便立即执行,执行顺序按照正常代码执行顺序从上往下执行

加上then : 正常执行完成后,执行then

环境3 添加then

let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";  resolve("then |")                             // 新加代码})promise.then((res) => {                         // 新加代码  showNode.innerHTML += res;                    // 新加代码})                                              // 新加代码showNode.innerHTML += "normal | ";              // 代码位置更改// 输出: promise | normal | then |复制代码
  • 当promise的状态由 pending 变为 fulfilled 后,对应使用的 then 才会执行。
  • 正常执行的代码处在 执行第一批 ,then 则处在第二批,当第一批执行完成后再执行第二批

外部setTimeout : 在then之后执行

环境4 添加到全局里的setTimeout

setTimeout(() => { showNode.innerHTML += "wait | " }, 0)  // 新加代码let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";  resolve("then |")})promise.then((res) => {  showNode.innerHTML += res;})showNode.innerHTML += "normal | ";// 输出: promise | normal | then | wait |复制代码
  • setTimeout会将代码执行推到线程末端,处在第三批

环境5 多个then

let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";  resolve("then |")})promise.then((res) => {  showNode.innerHTML += res;  return " next then | ";                       // 新加代码}).then((res) => {                              // 新加代码  showNode.innerHTML += res;                    // 新加代码  return " next next then | ";                  // 新加代码}).then((res) => {                              // 新加代码  showNode.innerHTML += res;                    // 新加代码})showNode.innerHTML += "normal | ";setTimeout(() => { showNode.innerHTML += "wait | " }, 0)// 输出: promise | normal | then | next then | next next then | wait |复制代码
  • 按照之前提到的内容,正常顺序执行的代码在第一批,then在第二批,setTimeout在第三批,
  • 第一批完成后执行第二批,第二批完成后执行第三批

promise中 的 setTimeout:使用setTimeout后,都被提到进程末尾,然后按照正常代码那样顺序输出

环境6 promise 中加入 setTimeout

let promise = new Promise((resolve, reject) => {  // 新加代码  setTimeout(() => { showNode.innerHTML += "promise wait | "; }, 0)   showNode.innerHTML += "promise | ";  resolve("then |")})promise.then((res) => {  showNode.innerHTML += res;  return " next then | ";}).then((res) => {  showNode.innerHTML += res;  return " next next then | ";}).then((res) => {  showNode.innerHTML += res;})showNode.innerHTML += "normal | ";setTimeout(() => { showNode.innerHTML += "wait | " }, 0)// 输出:promise | normal | then | next then | next next then |//      promise wait | wait |复制代码
  • 因为Promise在第一批,Promise中设置的setTimeout被提到了第三批
  • 在第三批执行过程中,流程也是从上往下顺序执行

环境7 外部setTimeout 在 promise 中的 setTimeout 之前

showNode.innerHTML += "normal | ";setTimeout(() => { showNode.innerHTML += "wait | " }, 0)  // 代码位置更改let promise = new Promise((resolve, reject) => {  setTimeout(() => { showNode.innerHTML += "promise wait | "; }, 0)    showNode.innerHTML += "promise | ";  resolve("then |")})promise.then((res) => {  showNode.innerHTML += res;  return " next then | ";}).then((res) => {  showNode.innerHTML += res;  return " next next then | ";}).then((res) => {  showNode.innerHTML += res;})// 输出: normal | promise | then | next then | next next then | wait | //       promise wait |复制代码

环境8 promose中用setTimeout包裹resolve

showNode.innerHTML += "normal | ";setTimeout(() => { showNode.innerHTML += "wait | " }, 0)let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";  setTimeout(() => { resolve("then |"); }, 0)     // 代码修改})promise.then((res) => {  showNode.innerHTML += res;  return " next then | ";}).then((res) => {  showNode.innerHTML += res;  return " next next then | ";}).then((res) => {  showNode.innerHTML += res;})// 输出: normal | promise | wait | then | next then | next next then |复制代码
  • 还是按照批次来思考, setTimeout在第一批中设定,里面执行的函数被提到第三批中。
  • promise只有状态变为 fulfilled 后才会触发相应的 then
  • 在第一批中将控制状态的 resolve() 提到第三批,等于将原本的第二批 then 所执行的内容全部提到第三批。
  • 第一批为正常顺序执行的代码,第二批为空,第三批按照从上到下的顺序执行。

环境9 将Promise外的setTimeout下移

showNode.innerHTML += "normal | ";let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";  setTimeout(() => { resolve("then |"); }, 0)     })promise.then((res) => {  showNode.innerHTML += res;  return " next then | ";}).then((res) => {  showNode.innerHTML += res;  return " next next then | ";}).then((res) => {  showNode.innerHTML += res;})setTimeout(() => { showNode.innerHTML += "wait | " }, 0) // 代码位置更改// 输出: normal | promise | then | next then | next next then | wait |复制代码

环境10 then中的setTimeout

showNode.innerHTML += "normal | ";let promise = new Promise((resolve, reject) => {  showNode.innerHTML += "promise | ";  setTimeout(() => { resolve("then |"); }, 0)})promise.then((res) => {  // 新加代码  setTimeout(() => { showNode.innerHTML += 'then wait | ' }, 0)    showNode.innerHTML += res;  return " next then | ";}).then((res) => {  showNode.innerHTML += res;  return " next next then | ";}).then((res) => {  showNode.innerHTML += res;})setTimeout(() => { showNode.innerHTML += "wait | " }, 0)// 输出: normal | promise | then | next then | next next then | wait | //      then wait |复制代码
  • 第一批:正常顺序执行代码。
  • 第二批:空
  • 第三批:被setTimeout提到线程末尾的
  • 第四批:在then中被setTimeout提到线程末尾
——————————

全文到此结束

本文按照自己的理解,按照 “分批次” 的思想进行讲解,希望能让文章显得更加通俗易懂。

如果有什么不对的地方,请在评论区指出,或者私信我。

你的建议可以让我的下一篇文章更加精彩

Thank you for watching

转载地址:http://gckix.baihongyu.com/

你可能感兴趣的文章
如何使用Core Text计算一段文本绘制在屏幕上之后的高度
查看>>
==和equals区别
查看>>
2010技术应用计划
查看>>
XML 节点类型
查看>>
驯服 Tiger: 并发集合 超越 Map、Collection、List 和 Set
查看>>
Winform开发框架之权限管理系统改进的经验总结(3)-系统登录黑白名单的实现...
查看>>
Template Method Design Pattern in Java
查看>>
MVC输出字符串常用四个方式
查看>>
LeetCode – LRU Cache (Java)
查看>>
JavaScript高级程序设计--对象,数组(栈方法,队列方法,重排序方法,迭代方法)...
查看>>
【转】 学习ios(必看经典)牛人40天精通iOS开发的学习方法【2015.12.2
查看>>
nginx+php的使用
查看>>
在 ASP.NET MVC 中使用异步控制器
查看>>
SQL语句的执行过程
查看>>
Silverlight开发历程—动画(线性动画)
查看>>
详解Linux中Load average负载
查看>>
HTTP 协议 Cache-Control 头——性能啊~~~
查看>>
丢包补偿技术概述
查看>>
PHP遍历文件夹及子文件夹所有文件
查看>>
WinForm程序中两份mdf文件问题的解决
查看>>