实现一个promise
const Promise2 = function(constructor) {
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
function resolve(value) {
if (self.status === 'pending') {
self.value = value;
self.status = 'resolved';
}
}
function reject(reason) {
if (self.status === 'pending') {
self.reason = reason;
self.status = 'rejected';
}
}
try {
constructor(resolve, reject);
} catch(e) {
reject(e);
}
}
Promise2.prototype.then = function(onFulfilled, onRejected) {
let self = this;
switch(self.status) {
case 'resolved':
onFulfilled(self.value);
break;
case 'rejected':
onRejected(self.reason);
break;
default:
}
}
// let instance = new Promise2((resolve, reject) => resolve(1));
// instance.then(res => console.log(res));
实现Promise.resolve、Promise.reject
- Promise.resolve(value) 方法返回一个以给定值解析后的Promise 对象。
- 如果这个值是一个promise,那么将返回这个promise;
- 如果这个值是thenable(即带有"then" 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;否则返回的promise将以此值完成。
- Promise.reject() 方法返回一个带有拒绝原因的Promise对象。
Promise.resolve2 = value => {
if (value && typeof value === "object" && (value instanceof Promise)) {
return value;
}
return new Promise(resolve => {
resolve(value);
})
}
Promise.resolve2(2).then(console.log);
Promise.reject2 = value => {
return new Promise((resolve, reject) => {
reject(value);
})
}
Promise.reject2(new Error('nishi shabi')).then(() => {
console.log("resolved");
}, error => {
console.log(error);
})
实现Promise.all
- Promise.all 的返回值是一个新的 Promise 实例。
- Promise.all 接受一个可遍历的数据容器,容器中每个元素都应是 Promise 实例。咱就是说,假设这个容器就是数组。
- 数组中每个Promise实例都成功时(由pendding状态转化为fulfilled状态),Promise.all 才成功。这些 Promise 实例所有的 resolve 结果会按照原来的顺序集合在一个数组中作为 Promise.all 的 resolve 的结果。
- 数组中只要有一个 Promise 实例失败(由pendding状态转化为rejected状态),Promise.all 就失败。Promise.all 的 .catch() 会捕获到这个 reject
Promise.all2 = function(promises = []) {
if (!promises.length) { return Promise.resolve([]); }
return new Promise((resolve, reject) => {
let resAll = [];
let len = promises.length;
promises.forEach(item => {
item.then(res => {
resAll.push(res);
if (resAll.length === len) {
resolve(resAll);
}
}).catch(error => {
reject(error);
})
});
})
}
let P1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
let P2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 1500);
});
Promise.all2([P1, P2]).then(res => {
console.log(res);
});
实现Promise.allSettled
- 不管是全部成功还是有部分失败,最终都会进入Promise.allSettled的.then回调中;
- 最后的返回值中,成功和失败的项都有status属性,成功时值是fulfilled,失败时是rejected;
- 最后的返回值中,成功含有value属性,而失败则是reason属性;
Promise.allSettled2 = (promises = []) => {
return new Promise((resolve, reject) => {
let len = promises.length;
let count = 0;
let resAll = [];
if (!len) {
resolve([]);
}
promises.forEach((item, index) => {
Promise.resolve(item).then(res => {
count += 1;
resAll[index] = {
status: "fulfilled",
value: res
};
if (count === len) {
resolve(resAll);
}
}).catch(error => {
count += 1;
resAll[index] = {
status: "rejected",
reason: error
};
if (count === len) {
resolve(resAll);
}
});
})
})
}
// 测试一下
const p1 = Promise.resolve(1)
const p2 = Promise.reject('err4')
const P = Promise.allSettled2([p1, p2]).then(res => {
console.log(res);
});
实现一个Promise.race
Promise.race2 = (promises = []) => {
return new Promise((resolve, reject) => {
promises.forEach(item => {
Promise.resolve(item).then(res => {
resolve(res);
}).catch(error => {
reject(error);
})
});
})
}
event loop执行顺序:
- 开始整个脚本作为一个宏任务执行;
- 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列;
- 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完;
- 执行浏览器UI线程的渲染工作;
- 检查是否有web worker任务,有则执行;
- 执行完本轮的宏任务,回到2,依次循环,直到宏任务和微任务全部队列为空;
微任务包括:
MutationObserver、Promise.then()或catch()、Promise为基础开发的其他技术,比如fetch API、V8的垃圾回收过程、Node独有的process.nextTick。
宏任务包括:
script、setTimeout、setInterval、setImmediate、I/O、UI rendering
注意: 在所有任务开始的时候,由于宏任务包括了script,所以浏览器会先执行一个宏任务,在这个过程中看到的延迟任务如setTimeout将放到下一轮宏任务执行
console.log("start");
setTimeout(() => {
console.log("setTimeout1");
}, 0);
(async function foo() {
console.log("async 1");
await asyncFunction();
console.log("async2");
})().then(console.log("foo.then"));
async function asyncFunction() {
console.log("asyncFunction");
setTimeout(() => {
console.log("setTimeout2");
}, 0);
new Promise((res) => {
console.log("promise1");
res("promise2");
}).then(console.log);
}
console.log("end");
/*
start
async 1
asyncFunction
promise1
foo.then
end
promise2
async2
setTimeout1
setTimeout2
**/
使用Promise实现红绿灯交替重复亮
红灯3秒亮一次,黄灯2秒亮一次,绿灯1秒亮一次;如何让三个灯不断交替重复亮灯?(用Promise实现)三个亮灯函数已经存在:
function red() {
console.log("red");
}
function green() {
console.log("green");
}
function yellow() {
console.log("yellow");
}
const light = (cb, timer) => {
return new Promise(resolve => {
setTimeout(() => {
cb();
resolve();
}, timer);
})
}
async function setup() {
await light(red, 3000);
await light(green, 2000);
await light(yellow, 1000);
setup();
}
setup();
实现有并行限制的 Promise 调度器
题目描述:JS 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个
addTask(1000,"1");
addTask(500,"2");
addTask(300,"3");
addTask(400,"4");
的输出顺序是:2 3 1 4
整个的完整执行流程:
一开始1、2两个任务开始执行
500ms时,2任务执行完毕,输出2,任务3开始执行
800ms时,3任务执行完毕,输出3,任务4开始执行
1000ms时,1任务执行完毕,输出1,此时只剩下4任务在执行
1200ms时,4任务执行完毕,输出4
class Scheduler {
constructor(limit) {
this.queue = [];
this.maxCount = limit;
this.runCounts = 0;
}
add(time, order) {
const promiseCreate = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(order);
resolve();
}, time);
});
}
this.queue.push(promiseCreate);
}
request() {
if (!this.queue.length || this.runCounts >= this.maxCount) {
return;
}
this.runCounts++;
// shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值
this.queue.shift()().then(() => {
this.runCounts--;
this.request();
});
}
taskStart() {
for (let i = 0; i < this.maxCount; i++) {
this.request();
}
}
}
const scheduler = new Scheduler(2);
scheduler.add(1000, 1);
scheduler.add(500, 2);
scheduler.add(300, 3);
scheduler.add(400, 4);
scheduler.taskStart();