原稿:语雀 · Promise 相关题目 · 原目录:面向面经学习 › Promise 相关题目
笔记正文
希望 1000ms 后输出 “0,1,2,3,4”
下列代码的输出,解释
如何修改,以实现目标
for (var a = 0; a < 5; a++) {
setTimeout(() => console.log(a), 1000);
}
上述代码打印出五个5,修改方案
// 方案一:保存参数
for (var a = 0; a < 5; a++) {
setTimeout((a) => console.log(a), 1000*a, a);
}
// 方案二:使用let
for (let a = 0; a < 5; a++) {
setTimeout(() => console.log(a), 1000*a);
}
// 方案三:使用promise
for (var a = 0; a < 5; a++) {
Promise.resolve(a).then((value) => {
setTimeout(() => {
console.log(value);
}, 1000 * value);
});
}
// 方案四:使用立即函数:使用IFEE函数体充当块级作用域,内部匿名函数成为IFEE闭包
for (var a = 0; a < 5; a++) {
(function (i) {
setTimeout(() => console.log(i), 1000 * i);
})(a);
}
看代码说输出,理由
console.log(1);
setTimeout(() => {
console.log(2);
});
new Promise((resolve) => {
console.log(3);
resolve("resolve");
console.log(4);
reject("error");
})
.catch((err) => {
console.log(err);
})
.then((res) => {
console.log(res);
});
Promise.resolve().then(() => {
console.log(5);
});
console.log(6);
输出顺序:1 3 4 6 5 resolve 2
1 3 4 6易得,主线程空闲后,首先检查微任务队列,依次为:(11行) catch()回调 <– (17行) then() 回调,放入栈中执行,因为第一个 promise转换为 resolved,所以 catch() 回调不会执行,它会把上一个 value 传递给下面的 then(),后者的回调立刻进入微任务队列,队列变成 :(17行) then()回调 <– (14行) then()回调,接下来才会输出 5 “resolve”,最后执行一个宏任务,输出2
console.log(1);
setTimeout(() => {
console.log(2);
Promise.resolve().then(() => {
console.log(3)
});
});
new Promise((resolve, reject) => {
console.log(4)
resolve(5)
}).then((data) => {
console.log(data);
})
setTimeout(() => {
console.log(6);
})
console.log(7);
输出顺序:1 4 7 5 2 3 6
async function async1() {
console.log('async1 start');//2
await async2();
console.log('async1 end');// 6
}
async function async2() {
console.log('async2');//3
}
console.log('script start');//1
setTimeout(function() {
console.log('setTimeout');//8
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');//4
resolve();
}).then(function() {
console.log('promise2');//7
});
console.log('script end');//5
1)代码补充 asyncGetValue(),使之实现 asyncGetValue(1,2).then(v => console.log(v));
function asyncAdd(a, b, callback) {
doAsyncWork(a, b).then(value => callback(value));
}
function asyncGetValue(a, b) {
.....
}
2)如果是实现 asyncGetValues(list),list是一个对象数组,类似于
const list = [
{a: 1, b: 2},
{a: 100, b: 200},
{a: 11, b: 21},
{a: 31, b: 41},
{a: 41, b: 51}];
function asyncGetValues(list) {
.....
}
3)在第三问的基础上实现并发控制,即有一个最大的并发数 maxConcurreent
解答:可以补全 asyncAdd,变成可执行的函数,方便验证
function asyncAdd(a, b, callback) {
Promise.resolve(a + b).then((value) => callback(value));
// doAsyncWork(a, b).then((value) => callback(value));
}
第一问:较简单,注意因为 asyncAdd 没有返回 promise,这里必须进行包装,向 asyncAdd 传入包装后的 resolve
function asyncGetValue(a, b) {
return new Promise((resolve) => asyncAdd(a, b, resolve));
}
第二问:注意使用 Promise.all
function asyncGetValues(list) {
let promises = [];
for (let item of list) {
promises.push(new Promise((resolve) => asyncAdd(item.a, item.b, resolve)));
}
return Promise.all(promises);
}
第三问:注意给 add() 传入的 caller 不能直接是 asyncAdd(item.a, item.b)
function asyncGetValues(list, max) {
let _max = max;
let _count = 0;
let _taskQueue = [];
function add(caller) {
return new Promise((resolve) => {
let task = createTask(caller, resolve);
if (_count < _max) task();
else _taskQueue.push(task);
});
}
function createTask(caller, resolve) {
return () => {
caller()
.then(resolve)
.finally(() => {
if (_taskQueue.length) {
let task = _taskQueue.shift();
task();
_count--;
}
});
_count++;
};
}
let promises = [];
for (let item of list) {
let promise = add(
() => new Promise((resolve) => asyncAdd(item.a, item.b, resolve))
);
promises.push(promise);
}
return Promise.all(promises);
}