(二)Promise

一、、同步任务(synchronous Tasks)、异步任务(Asynchronous Tasks)(宏任务与微任务)

	前言
		js 是一门单线程语言,所以任务都是按顺序执行的,只有当上一个任务结束后,才会执行下一个任务,不可同事执行多个任务。
		javascript语言将任务的执行模式分为两种:同步任务和异步任务(宏任务和微任务都属于异步任务)

1、同步任务

所谓同步任务,就是非耗时任务,在主线程当中直接执行的任务
(1)变量赋值和运算:

let a = 5;  
let b = a * 2;  
console.log(b); // 输出 10

(2)直接调用的函数:

function greet() {  
  console.log('Hello, world!');  
}  
greet(); // 输出 "Hello, world!"

(3)循环和条件语句:

for (let i = 0; i < 5; i++) {  
  console.log(i);  
}  
// 输出 0, 1, 2, 3, 4

(4)对象和方法调用:

const obj = {  
  name: 'Alice',  
  sayHello: function() {  
    console.log(`Hello, my name is ${this.name}!`);  
  }  
};  
obj.sayHello(); // 输出 "Hello, my name is Alice!"

(5)数组和字符串操作:

const arr = [1, 2, 3, 4, 5];  
const sum = arr.reduce((acc, val) => acc + val, 0);  
console.log(sum); // 输出 15  
  
const str = 'Hello';  
const upperStr = str.toUpperCase();  
console.log(upperStr); // 输出 "HELLO"

(6)当async/await的任务当中,并没有返回值时候

Promise.resolve().then(() => {
  console.log(1);
});
let a = async () => {
  await console.log(2);
  return console.log(20);
};

a();
//输出结果:
2
1
20

注意:返回值是异步任务

2、异步任务

宏任务(macro-task)
script(理解为外层同步代码)、setTimeout/setInterval 、postMessage、requestAnimationFrame、MessageChannel、UI rending/UI事件、setmmediate与I/O(Node.js环境)
微任务(micro-task)
Promise.then()、await后面的代码、MutaionObserver(html5新特性)、proxy、process.nextTick(Node.js)
执行顺序
1、同步代码
2、所有微任务
3、第一个宏任务
4、所有新添加的微任务
5、下一个宏任务
核心要点
1、JavaScript引擎总是会先执行同步代码,然后再执行异步代码(同步先行,异步靠后)
2、微任务的优先级高于宏任务
3、微任务可以在Event Loop中插队
在这里插入图片描述
JS的执行机制是:

首先,判断JS是同步还是异步,同步进入主线程,异步进入Event table
其次,异步任务在Event table中注册函数,当满足特定的条件,被推入Event queue
最后,同步任务进入主线程后一直执行,直到主线程空闲后,才会去Event queue中查看是否有可执行的异步任务,如果有就推入主线程中执行。
循环以上三步执行,这就是Event loop。
执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的【事件队列】里
当前宏任务执行完成后,会查看微任务的【事件队列】,并将里面全部的微任务依次执行完

二、输出顺序问题

1、

console.log(1)

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

new Promise(resolve=>{
    console.log(5)
    resolve(3)
}).then(res=>{
    console.log(res)
})

console.log(2)
// 输出结果: 1 5 2 3 4
 这里只有一个需要注意的地方就是Promise,.then方法才是微任务,console.log(5)是同步任务

2、

console.log(1);

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

new Promise((resolve) => {
    console.log(5);
    resolve(3);
    new Promise((resolve) => {
        console.log(6);
        resolve(7);
    }).then((res) => {
        console.log(res);
    });
}).then((res) => {
console.log(res);
});

console.log(2);
//输出结果: 1 5 6 2 7 3 4
同步任务 1562 微任务:73 宏任务:4 
这里需要注意的地方是Promise.then()这个微任务放到事件队列的顺序,并不是执行到resolve()方法就会将这个微任务加入到事件队列,而是要执行到.then方法的才会被加入到事件队列,所以 67 前面。(要被执行的微任务会被加入到事件队列,先进先出)

构造函数式同步执行的,.then是异步执行
3、

setTimeout(() => {
    console.log(1);
}, 0);
async function test1() {
    console.log(2)
}
async function test2() {
    await test1()
    console.log(3)
}
test2()

new Promise((resolve) => {
    console.log(4);
    resolve(5);
    new Promise((resolve) => {
        console.log(6);
        resolve(7);
    }).then((res) => {
        console.log(res);
    });
}).then((res) => {
console.log(res);
});
//输出结果:2 4 6 3 7 5 1
同步任务:246 微任务:357 宏任务:1 
注意:await ,await后面一般跟一个Promise对象,如果后面不是Primise对象会被转成Promise对象,await会暂停当前的async function的执行,等待await表达式后面的Promise处理完成后才会继续执行。

3、

document.onclick = function() {
    console.log("1");
};
console.log(2);

// 3秒之后才会提交到任务队列中
setTimeout(function() {
    console.log(3);
}, 3000);

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

同步任务:2 宏任务:3 41)没有点击: 输出结果: 2 4 323秒内点击:输出结果:2 4 1 333秒后点击:输出结果 2 4 3 1

三、常见问题

1、为什么说script是一个宏任务?
script是脚本,这被当作是一个宏函数。

<!-- 脚本 1 -->
<script>
console.log('1-1')
setTimeout(() => console.log('1-2'), 0)

new Promise((resolve, reject) => {
    console.log('1-3')
    resolve('1-4')
}).then((res) => {
    console.log(res)
})

console.log('1-5')
</script>

<!-- 脚本 2 -->
<script>
console.log('2-1')
setTimeout(() => console.log('2-2'), 0)

new Promise((resolve, reject) => {
    console.log('2-3')
    resolve('2-4')
}).then((res) => {
    console.log(res)
})

console.log('2-5')
</script>

//输出结果 :1-1、1-3、1-5、1-4、2-1、2-3、2-5、2-4、1-2、2-2

2、宏任务与微任务的理解和差异
微任务宏任务差异表

宏任务微任务
是否重新渲染页面不会
是否需要其他异步线程的支持需要不需要
宏任务与微任务的发起者宿主(node、浏览器)js引擎
具体事件script、setTimeout/setInterval、postMessage、MessageChannel、requestAnimaionFrame、UI rending/UI事件、setImmediate与I/O(Node.js环境)Promise.then()、await 后面的代码、MutaionObserver(html5新特性)、proxy、process.nextTick(node.js)

3、宏任务与微任务产生的误差

console.log(1)
new Promise((resolve,reject)=>{
    console.log(2)
    resolve(3)
}).then(res=>{
    console.log(res)
    const targetTime = new Date().getTime()+3000
    let isEnd = false

    // 延时三秒
    while(!isEnd){
        const currentTime = new Date().getTime()
        if (targetTime <= currentTime){
            isEnd = true
        }
    }
})
setTimeout(() => console.log(4), 0)
console.log(5)
//执行结果:1 2 5 3 4  
注意 console.log(4)是在3秒后被输出
同步任务:1 2 5 微任务:3 宏任务:4  
因为在执行promise微任务耗费了3秒, setTimeout的第二个参数仅仅表示最少延迟时间,而非确切的时间。
其他具有回调方法的宏任务也基本是这样。 即使是在异步任务中的做费时等的延迟操作,也会影响到同为异步任务的宏任务,在代码开发中一定要注意比较耗时的代码所产生的影响!

4、通过一个例子加深了解

<body>
<div class="demo"></div>
<script>
window.onload = function() {
    const div = document.querySelector(".demo");

    Promise.resolve().then(() => {
        alert("promise0");
    });
    alert('同步0')

    // 宏任务1
    setTimeout(() => {
        Promise.resolve().then(() => {
            alert("promise1");
        });
        div.textContent = "元素div1";
        alert("settimeout1");
    }, 0);

    // 宏任务2
    setTimeout(() => {
        div.textContent = "元素div2";
        alert("settimeout2");
    }, 0);
};
</script>
</body>
//输出结果:
(1)alert('同步0') (同步任务)
(2)alert("promise0");(微任务)
(3)alert("settimeout1");(settimeout1宏任务)
(4)div.textContent = "元素div1";(页面渲染:页面中的'元素div1'被渲染展示)
(5)alert("promise1");(settimeout1宏任务中的微任务)
(6)alert("settimeout2");(settimeout2宏任务)
(7)div.textContent = "元素div2";(页面渲染:页面中的文字'元素div1'=>'元素div2')
之所以用alert,是因为alert会阻塞线程,方便我们观察页面渲染,这个例子主要想表达:

每个宏任务执行完毕并清空里面的微任务后,会进行一次页面渲染
在这里插入图片描述

参考:
https://zhuanlan.zhihu.com/p/618003341
https://baijiahao.baidu.com/s?id=1761241446490028512&wfr=spider&for=pc
https://www.cnblogs.com/sunupo/p/15566501.html
https://blog.csdn.net/qq_41131745/article/details/127004662
https://www.cnblogs.com/guoyeqiang/p/8317582.html
https://cloud.tencent.com/developer/article/2336215

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值