首页 > 其他分享 >JS基础 任务管理

JS基础 任务管理

时间:2023-03-24 13:01:19浏览次数:42  
标签:setTimeout console log 基础 JS 任务 Promise 执行


阅读目录

  • 任务管理
  • 原理分析
  • 脚本加载
  • 定时器
  • 微任务
  • 实例操作
  • 进度条
  • 任务分解

任务管理

JavaScript 语言的一大特点就是单线程,也就是说同一个时间只能处理一个任务。为了协调事件、用户交互、脚本、UI 渲染和网络处理等行为,防止主线程的不阻塞,(事件循环)Event Loop 的方案应用而生。

JavaScript 处理任务是在等待任务、执行任务 、休眠等待新任务中不断循环中,也称这种机制为事件循环。

  • 主线程中的任务执行完后,才执行任务队列中的任务
  • 有新任务到来时会将其放入队列,采取先进先执行的策略执行队列中的任务
  • 比如多个 setTimeout 同时到时间了,就要依次执行

任务包括 script(整体代码)、 setTimeout、setInterval、DOM渲染、DOM事件、Promise、XMLHTTPREQUEST等

原理分析

下面通过一个例子来详细分析宏任务与微任务

console.log("wgchen");
setTimeout(function() {
  console.log("定时器");
}, 0);

Promise.resolve()
.then(function() {
  console.log("promise1");
})
.then(function() {
  console.log("promise2");
});

console.log("blog.cs");

JS基础 任务管理_前端


1、先执最前面的宏任务 script,然后输出

script start

2、然后执行到 setTimeout 异步宏任务,并将其放入宏任务队列,等待执行
3、之后执行到 Promise.then 微任务,并将其放入微任务队列,等待执行
4、然后执行到主代码输出

script end

5、主线程所有任务处理完成
6、通过事件循环遍历微任务队列,将刚才放入的 Promise.then 微任务读取到主线程执行,然后输出。

promise1

7、之后又执行 promse.then 产生新的微任务,并放入微任务队列
8、主线程任务执行完毕
9、现次事件循环遍历微任务队列,读取到 promise2 微任务放入主线程执行,然后输出

promise2

10、主线程任务执行完毕

11、此时微任务队列已经无任务,然后从宏任务队列中读取到 setTimeout 任务并加入主线程,然后输出。

setTimeout

JS基础 任务管理_前端_02

脚本加载

引擎在执行任务时不会进行DOM渲染,所以如果把 script 定义在前面,要先执行完任务后再渲染DOM,建议将 script 放在 BODY 结束标签前。

定时器

定时器会放入异步任务队列,也需要等待同步任务执行完成后执行。

下面设置了 6 毫秒执行,如果主线程代码执行10毫秒,定时器要等主线程执行完才执行。

HTML标准规定最小时间不能低于4毫秒,有些异步操作如DOM操作最低是16毫秒,总之把时间设置大些对性能更好。

setTimeout(func,6);

下面的代码会先输出 wgchen.blog.cs.net 之后输出 ycc

setTimeout(() => {
  console.log("ycc");
}, 0);
console.log("wgchen.blog.cs.net");

JS基础 任务管理_开发语言_03


这是对定时器的说明,其他的异步操作如事件、XMLHTTPREQUEST 等逻辑是一样的

微任务

微任务一般由用户代码产生,微任务较宏任务执行优先级更高,Promise.then 是典型的微任务,实例化 Promise 时执行的代码是同步的,便then注册的回调函数是异步微任务的。

任务的执行顺序是同步任务、微任务、宏任务所以下面执行结果是 1、2、3、4

setTimeout(() => console.log(4));

new Promise(resolve => {
  resolve();
  console.log(1);
}).then(_ => {
  console.log(3);
});

console.log(2);

我们再来看下面稍复杂的任务代码

setTimeout(() => {
  console.log("定时器");

  setTimeout(() => {
    console.log("timeout timeout");
  }, 0);

  new Promise(resolve => {
    console.log("settimeout Promise");
    resolve();
  }).then(() => {
    console.log("settimeout then");
  });

}, 0);

new Promise(resolve => {
  console.log("Promise");
  resolve();
}).then(() => {
  console.log("then");
});

console.log("wgchen");

JS基础 任务管理_开发语言_04

实例操作

进度条

下面的定时器虽然都定时了一秒钟,但也是按先进行出原则,依次执行

let i = 0;
setTimeout(() => {
  console.log(++i);
}, 1000);

setTimeout(() => {
  console.log(++i);
}, 1000);

JS基础 任务管理_任务队列_05


下面是一个进度条的示例,将每个数字放在一个任务中执行

JS基础 任务管理_javascript_06

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>wgchen</title>
  <link rel="shortcut icon" href="#" />
</head>

<body>
  <style>
    body {
      padding: 30px;
    }
    #hd {
      height: 30px;
      background: yellowgreen;
      width: 0;
      text-align: center;
      font-weight: bold;
    }
  </style>
  <div id="hd"></div>
</body>

<script>
  function view() {
    let i = 0;
    (function handle() {
      hd.innerHTML = i + "%";
      hd.style.width = i + "%";
      if (i++ < 100) {
        setTimeout(handle, 20);
      }
    })();
  }
  view();
  console.log("定时器开始了...");
</script>

</html>

任务分解

一个比较耗时的任务可能造成游览器卡死现象,所以可以将任务拆分为多小,小异步小任务执行。下面是一个数字统计的函数,我们会发现运行时间特别长。

JS基础 任务管理_任务队列_07

console.time("runtime");

function hd(num) {
  let count = 0;
  for (let i = 0; i <= num; i++) {
    count += i;
  }
  console.log(count);
  console.timeEnd("runtime");
}

let num=987654321;
hd(num);
console.log("wgchen.blog.cs.net"); 
//需要等待上面执行完才会执行

现在把任务分解成小块放入任务队列,游览器就不会出现卡死的现象了,也不会影响后续代码的执行。

JS基础 任务管理_前端_08

console.time("runtime");
let count = 0;
let num = 987654321;

function hd() {
  for (let i = 0; i < 100000000; i++) {
    if (num <= 0) break;
    count += num--;
  }
  if (num > 0) {
    console.log(num);
    setTimeout(hd);
  } else {
    console.log(num);
    console.log(count);
  }
}
hd();
console.log("wgchen.blog.cs.net"); //立刻显示出来

交给微任务处理是更好的选择

async function hd(num) {
  let res = await Promise.resolve().then(_ => {
    let count = 0;
    for (let i = 0; i < num; i++) {
      count += num--;
    }
    return count;
  });
  console.log(res);
}
hd(987654321);
console.log("wgchen.blog.cs.net");

JS基础 任务管理_主线程_09


标签:setTimeout,console,log,基础,JS,任务,Promise,执行
From: https://blog.51cto.com/u_13571520/6147116

相关文章

  • JS基础 模块设计
    阅读目录模块设计使用分析实现原理基础知识标签使用模块路径延迟解析模块默认运行在严格模式模块都有独立的顶级作用域预解析导入导出导出模块具名导入批量导入导入建议别名......
  • JS基础 原型与继承
    阅读目录原型基础原型对象使用数组原型对象的concat方法完成连接操作默认情况下创建的对象都有原型。以下x、y的原型都为元对象Object,即JS中的根对象创建一个极简对象(......
  • requireJS 源码(二) data-main 的加载实现
    requireJS源码(二)data-main的加载实现(一)requireJs的整体结构:requireJS源码前192行,是一些变量的声明,工具函数的实现以及对三个全局变量(requirejs,require,def......
  • requireJS 源码(一) require() 为何可以全局使用
    requireJS源码(一)require()为何可以全局使用requireJS源码加注释总共不到2100行。我看的requireJs版本是2.19。 总体结构如下。......
  • requireJS 源码(三) data-main 的加载实现
    requireJS源码(三)data-main的加载实现(一)入口通过data-main去加载JS模块,是通过  req(cfg) 入口去进行处理的。为了跟踪,你可以在此加断点进行调试跟......
  • Vue.js 路由简介
    路由理解:一个路由(route)就是一组映射关系(key-value),多个路由需要路由器(router)进行管理。前端路由:key是路径,value是组件。......
  • 计算机核心基础知识
    目录’一、编程与编程语言(1)、什么是语言(2)、什么是编程(3)、什么是编程语言二、计算机本质三、计算机五大组成部分(1)、控制器(2)、运算器(3)、存储器(4)、输出设备(5)......
  • python apscheduler 定时任务的基本使用-4-cron触发器的使用
    pythonapscheduler定时任务的基本使用-4-cron触发器的使用1、前言cron触发器,当前时间与cron表达式匹配时,执行任务,等同于UNIX的cron。官网cron2、参数说明参数如下,除......
  • 这个是我在学习基础知识的一些照片,方便后期可以查看
                                                        ......
  • js保存文件到本地
    使用原生方法保存文件到本地基本流程确定要保存的文本、保存格式及保存文件类型;根据保存格式生成url链接,设置文件的下载地址;创建一个a标签(即a标签指向的就是我们要......