1 题目(1)
1.1 题目背景:分享@洛千陨 珍藏题
const p1 = () => (new Promise((resolve, reject) => {
console.log(1);
let p2 = new Promise((resolve, reject) => {
console.log(2);
const timeOut1 = setTimeout(() => {
console.log(3);
resolve(4);
}, 0)
resolve(5);
});
resolve(6);
p2.then((arg) => {
console.log(arg);
});
}));
const timeOut2 = setTimeout(() => {
console.log(8);
const p3 = new Promise(reject => {
reject(9);
}).then(res => {
console.log(res)
})
}, 0)
p1().then((arg) => {
console.log(arg);
});
console.log(10);
输出结果:1 2 10 5 6 8 9 3
输出结果分析
- 思路:
同步->异步
- 疑问:为什么先5后6?
宏任务队列
:8 9 3 4
(8-9这一块都是属于setTimeout里面的,下一轮 Event Loop再执行;resolve(5)后不输出4)
微任务队列
:5 6
(为什么先5后6, 因为在p2定义的时候会执行promise内部的代码, resolve(5)时有下面p2.then接收就会打印5)
JS主线程-同步代码
:1 2 10
注意点
- p1是个返回1个promise对象的普通函数需要p1()执行,p1().then接收回调;p2是个promise对象,p2.then接收回调。
- Promise 第一个参数是成功时的回调resolve, reject只是变量名。
const p3 = new Promise(reject => {
reject(9);
}).then(res => {
console.log(res)
})
1.2 延伸变形一
const p1 = () => (new Promise((resolve, reject) => {
console.log(1);
resolve(6);
let p2 = new Promise((resolve, reject) => {
console.log(2);
const timeOut1 = setTimeout(() => {
console.log(3);
resolve(4);
}, 0)
resolve(5);
});
p2.then((arg) => {
console.log(arg, 'p2 then');
});
}));
p1().then((arg) => {
console.log(arg,'p1 then');
});
console.log(10);
输出结果:1 2 10 5 6 8 9 3
问题: 为什么'6'在'5'前面还是先输出'5'
?!!
答:这里p1()调用->执行了p2.then,再执行p1.then,所以’5’比’6’先输出
1.3 延伸变形二
const p1 = () => (new Promise((resolve, reject) => {
console.log(1);
resolve(6);
let p2 = new Promise((resolve, reject) => {
console.log(2);
const timeOut1 = setTimeout(() => {
console.log(3);
resolve(4);
}, 0)
resolve(5);
});
p2.then((arg) => {
console.log(arg);
return 'hello'
}).then((value) => {
console.log(value)
});
}));
const timeOut2 = setTimeout(() => {
console.log(8);
const p3 = new Promise(reject => {
reject(9);
}).then(res => {
console.log(res)
})
}, 0)
p1().then((arg) => {
console.log(arg);
});
console.log(10);
输出结果:
1 2 10 5 6 hello 8 9 3
输出结果分析
- 疑问:为什么’6’比’hello’先打印?
答:参照源码,promise的then方法里面会返回一个promise。
①p2第一个then里的代码推入微任务队列(第一个),p1.then里的代码推入微任务队列(第二个);
②现在来执行第一个微任务打印'5'
,return 'hello’会把p2第二个then里的代码推入微任务队列(第三个);
③执行第二个微任务打印'6'
;
④执行第三个微任务打印'hello'
。
promise的源码参考我的另一篇博客:Promise高级版 - 通过输出题理解「Promise源码」
2 题目(2)
class Scheduler {
constructor(max) {
this.max = max
this.count = 0
this.queue = new Array()
}
async add(promiseCreator) {
if (this.count >= this.max) {
await new Promise((resolve, reject) => {
this.queue.push(resolve)
})
}
this.count++
const res = await promiseCreator()
this.count--
if (this.queue.length) {
this.queue.shift()()
}
console.log('res: ', res)
return res
}
}
const timeout = (time) => new Promise(resolve => {
console.log('100')
setTimeout(resolve, time)
})
const scheduler = new Scheduler(2)
const addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => {console.log(order); return 'timeout'})
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
输出结果:
100
100
res: undefined
100
2
res: undefined
100
3
res: undefined
1
res: undefined
4
输出结果分析
- Part 1:
(1)addTask1000、addTask500:
走两次到这儿
this.count++
const res = await promiseCreator(); 都输出’100’,先打印2个'100'
(2)addTask300、addTask400:
/** 这个new Promise单纯只是为了创建个微任务去等,前面加了await,没有resolve()是不会往下走的 */
await new Promise((resolve, reject) => {
this.queue.push(resolve);
}); - Part 2:
(3)500ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
;
(4)∵this.queue.shift()()即resolve()是同步代码,
addTask300走到这儿
this.count++
const res = await promiseCreator();
∴先打印下一个'100'
再return res打印'2'
- Part 3:
(5)接下来同理,300ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
;
(6)∵this.queue.shift()()即resolve()是同步代码,
addTask400走到这儿
this.count++
const res = await promiseCreator();
∴先打印下一个'100'
再return res打印'3'
- Part 4:
(7)1000ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
;
(8)没有下一个’100’了,return res打印'1'
; - Part 5:
(9)400ms的timeout执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
;
(10)没有下一个’100’了,return res打印'4'
;
Promise基本概念
可参考我的另外一篇博客:ECMAScript 6 Promise - Promise