ES6 Promise(3)

接着上面两篇笔记归纳下Promise的学习笔记

同步异步执行顺序

注意:Promise构造函数的内部,执行顺序是同步的。等内部执行完成后,再选择调用thencatch方法,then方法执行是异步的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
console.log(1);
// 注意:Promise构造函数的回调函数(参数)是同步执行的
// 它的then()是异步任务(微任务)
let p = new Promise(resolve => {
console.log(2);
resolve();
console.log(3);
});
console.log(4);
p.then(() => {
console.log(5);
})
console.log(6);
/*
1
2
3
4
6
5
*/

注意:
Promise构造函数的回调函数(参数)是同步执行的,它的then()是异步任务
resolve()后p状态改变,相当于调用了then()的参数函数,** p.then()是异步任务,所以在本轮事件循环中所有同步任务执行完以后才会执行,所以5在最后打印**


把同步任务转为异步任务

72-74:创建一个函数createAsyncTask()用于将传入的同步任务syncTask转换为已经决议为成功的Promise实例,由于已成功的状态,该实例会立即调用then()的第一个回调函数:把syncTask传给syncTask()并立即执行syncTask()
76-81:调用这个函数createAsyncTask(),往里传入一个thenable对象作为参数。
那么这个参数就会使用Promise.resolve()将自己变成 Promise实例,这个Promise实例执行完后返回2并成为已成功的状态,所以就会触发then()的第一个回调函数,该回调函数接收Promise实例返回的2作为参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function createAsyncTask(syncTask) {
/*
Promise.resolve() 将 syncTask 封装成一个已解决的 Promise 实例
该 Promise 实例的解决值就是传入的 syncTask 函数本身
由于已解决的状态,该实例会立即调用then()的第一个回调函数
then 的参数 result 是前面封装在 Promise 中的解决值 syncTask 函数
所以实际是执行了 syncTask 函数
*/
return Promise.resolve(syncTask).then(result => result());
// 注意:Promise.resolve()注册的是微任务而不是立即执行
}

const asyncFunc = () => {
console.log("我变成了异步任务! ! !");
return 1 + 1;
}
// createAsyncTask 执行完后会触发 then
createAsyncTask(asyncFunc).then(res => {
console.log(res); // 2
});
console.log("我是同步任务!");
/*
我是同步任务!
我变成了异步任务! ! !
2
*/

createAsyncTask 的流程如下:

  1. 首先,将同步函数 syncTask 包装在 Promise.resolve 中,创建一个已解决的 Promise 实例,并将其添加到微任务队列中。
  2. 当前任务执行完成后,微任务队列中的 Promise 实例会触发它的成功状态,并执行 .then 方法中的回调函数。
  3. 回调函数中的 result 参数是前面包装的 syncTask 函数,然后通过 result() 的调用来执行这个函数。

注意:虽然 syncTask 本质上是同步函数,但由于它被包装在 Promise.resolve 中,它的执行会被推迟到微任务队列中,从而在当前任务完成后执行。

需要了解:
当你调用 Promise.resolve(value) 时,value 的解析会被放入微任务队列,而不是像普通的Promise定义函数一样立即执行
当你在 Promise 中返回一个值,无论是直接的值还是通过 resolve() 返回,这个值都会被传递给 then 方法注册的回调函数

  1. 首先,同步任务执行,打印出 "我是同步任务!"
  2. 然后,createAsyncTask 函数内部的回调函数执行,打印出 "我变成了异步任务! ! !"。随后,它返回 1 + 1 的结果,即 2
  3. 接着,Promise 实例进入成功状态,触发了 .then() 注册的回调函数,将 2 作为参数传递给回调函数,然后打印出 2

小案例

代码
可以看到3张图片的加载时间是不同的,而是在最后一张图片加载完成后页面才显示出图片:
结果

注意

事件函数绑定时不能使用img.onload = resolve(img);这样图片还没加载完成,在赋值阶段函数resolve(img)就直接被调用了

检验错误

可以增加一个检验错误,多往数组中放入一个src
检验错误代码
结果就会返回我们在loadImg()中的onerror()中返回的错误对象e:
结果


总结

  • Promise 改善了传统回调造成的代码难维护、控制反转的问题。
  • Promise是异步的,但Promise构造函数中代码的执行时同步的。
  • 如果Promise.all()接收的是空数组,那么马上会被决议为成功。
  • 如果Promise.race()接收的是空数组,那么会永远挂起。
  • catch()返回的Promise实例,可以无线捕获错误问题(链式)。

Promise.resolve方法的传参

  • 如果 resolve() 接收的是普通的值,就会立即被决议为成功,直接传递这个值
  • 如果 resolve() 接收的是一个Promise实例,则返回这个Promise实例
  • 如果 resolve() 接收的是一个thenable对象,则会把该对象包装成Promise实例并立即执行该thenable对象的then()

Promise.reject方法的传参

Promise.reject()会产生一个决议失败的Promise实例,并直接传递接收到的参数。(不会有任何处理,假设参数是thenable对象,那么thenable对象也会被直接作为错误信息传递例子