Promise
类式实现
class MyPromise {
constructor(executor) {
this.state = 'pending'; // resolved rejected
this.value = null;
this.fns = [];
const resolve = (val) => {
if (this.state === 'pending') {
this.state = 'resolved';
this.value = val;
this.fns.forEach(({ resolveFn }) => resolveFn(val));
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.value = reason;
this.fns.forEach(({ rejectFn }) => rejectFn(reason));
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(resolveFn, rejectFn) {
if (typeof resolveFn !== 'function') {
resolveFn = (value) => value;
}
if (typeof rejectFn !== 'function') {
rejectFn = (reason) => {
throw new Error(reason);
};
}
return new MyPromise((resolve, reject) => {
const handle = (method) => {
try {
const result = method(this.value); // 获取调用返回结果
// 判断这个结果是不是promise的实例,是则调用这个promise然后传入resolve,reject
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
// 如果不是promise,就直接变成成功的值
resolve(result); // 直接存起来
}
// 如果上面执行的有抛出异常,则表明出现错误,直接调用reject
} catch (error) {
reject(error);
}
};
if (this.state === 'resolved') {
handle(resolveFn);
} else if (this.state === 'rejected') {
handle(rejectFn);
} else {
this.fns.push({
resolveFn() {
handle(resolveFn);
},
rejectFn() {
handle(rejectFn);
},
});
}
});
}
catch(rejectFn) {
return this.then(undefined, rejectFn);
}
finally(callback) {
return this.then(
(value) => MyPromise.resolve(callback()).then(() => value),
(reason) => MyPromise.reject(callback()).then(() => reason)
);
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(value);
});
}
}
class MyPromise {
constructor(executor) { // executor执行器
this.status = 'pending' // 等待状态
this.value = null // 成功或失败的参数
this.fulfilledCallbacks = [] // 成功的函数队列
this.rejectedCallbacks = [] // 失败的函数队列
const that = this
function resolve(value) { // 成功的方法
if (that.status === 'pending') {
that.status = 'resolved'
that.value = value
that.fulfilledCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法
}
}
function reject(value) { //失败的方法
if (that.status === 'pending') {
that.status = 'rejected'
that.value = value
that.rejectedCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
if (this.status === 'pending') {
// 等待状态,添加回调函数到成功的函数队列
this.fulfilledCallbacks.push(() => {
onFulfilled(this.value)
})
// 等待状态,添加回调函数到失败的函数队列
this.rejectedCallbacks.push(() => {
onRejected(this.value)
})
}
if (this.status === 'resolved') { // 支持同步调用
console.log('this', this)
onFulfilled(this.value)
}
if (this.status === 'rejected') { // 支持同步调用
onRejected(this.value)
}
}
}
// 测试
function fn() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if(Math.random() > 0.6) {
resolve(1)
} else {
reject(2)
}
}, 1000)
})
}
fn().then(
res => {
console.log('res', res) // res 1
},
err => {
console.log('err', err) // err 2
})
方法实现
/**
* Promise构造函数
* executor: 内部同步执行的函数(resolve, reject) => {}
* new Promise((resolve, reject) => {
* setTimeout(() => { resolve(42); }, 1000);
* })
*/
function Promise2(executor) {
// 初始状态
this.PromiseState = "pending";
// 初始结果
this.PromiseResult = null;
// 保存回调函数
this.callbacks = [];
const self = this;
// resolve函数
function resolve(value) {
// 判断状态,让Promise对象只能修改一次
if(self.PromiseState !== "pending") return;
// 修改状态
self.PromiseState = "fulfilled";
// 修改结果
self.PromiseResult = value;
// 调用回调函数
setTimeout(() => {
self.callbacks.forEach(element => {
element.onResolved(value);
});
});
}
// reject函数
function reject(reason) {
// 判断状态,让Promise对象只能修改一次
if(self.PromiseState !== "pending") return;
// 修改状态
self.PromiseState = "rejected";
// 修改结果
self.PromiseResult = reason;
// 调用回调函数
setTimeout(() => {
self.callbacks.forEach(element => {
element.onRejected(reason);
});
});
}
// 同步调用执行器函数
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
Promise2.prototype.then = function(onResolved, onRejected) {
if(typeof onResolved !== "function") {
onResolved = value => value;
}
if(typeof onRejected !== "function") {
onRejected = reason => {
throw new Error(reason);
}
}
// 固定返回一个Promise对象,这里我们称为newPro对象,供下一环节使用
// 注意这里是箭头函数,所以里面this指向oldPro对象(最初创建的Promise对象,称为oldPro)
return new Promise2((resolve, reject) => {
function handle(callback) {
try {
let result = callback(this.PromiseResult);
// 当result为Promise对象,这里我们称为resultPro,这个resultPro是外部自定义的
if(result instanceof Promise) {
// then方法将v函数压入resultPro对象的callbacks数组里,
// 当resultPro对象执行resolve函数时触发callbacks数组执行v函数,
// 执行v函数触发newPro对象的resolve函数,继而触发下一环节Promise对象执行onResolved函数
result.then(
// 该onResolved函数这里我们称为v函数,参数值为resultPro对象执行resolve函数时传入的值
v => {
// resolve为Promise构造函数内置函数
resolve(v);
},
r => {
reject(r);
}
);
} else {
// 触发newPro对象的resolve函数,并将result值向下一环节Promise对象的onResolved函数传递
resolve(result);
}
} catch (error) {
reject(error);
}
}
if(this.PromiseState === "pending") {
// 将then方法的onResolved函数压入oldPro对象的callbacks数组,供oldPro执行resolve方法调用
this.callbacks.push({
onResolved: (value) => {
handle.call(this, onResolved);
},
onRejected (reason) {
handle.call(this, onRejected);
}
});
}
if(this.PromiseState === "fulfilled") {
setTimeout(() => {
handle(onResolved);
})
}
if(this.PromiseState === "rejected") {
setTimeout(() => {
handle(onRejected);
})
}
});
}
其他
function MyPromise(executor) {
var self = this;
self.status = 'pending'
self.value = undefined
self.reason = undefined
self.onResolved = []
self.onRejected = []
function resolve(value) {
if (self.status === 'pending') {
self.status = 'fulfilled'
self.value = value
self.onResolved.forEach(fn => fn())
}
}
function reject(reason) {
if (self.status === 'pending') {
self.reason = reason
self.status = 'rejected'
self.onRejected.forEach(fn => fn())
}
}
// executor(resolve, reject)
try {
executor(resolve, reject)
}catch(e) {
reject(e)
}
}
MyPromise.prototype.then = function(onfulfilled, onrejected) {
let self = this
if (self.status === 'fulfilled') {
onfulfilled(self.value)
}
if (self.status === 'rejected') {
onrejected(self.reason)
}
if (self.status === 'pending') {
self.onResolved.push(function() {
onfulfilled(self.value)
})
self.onRejected.push(function() {
onfulfilled(self.reason)
})
}
}
var p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000);
})
p.then((value) => {
console.log(value)
}, (reason) => {
console.log('err', reason);
})
Promise.all() 方法
- 接收一个Promise 实例的数组或具有 Iterator 接口的对象作为参数
- 这个方法返回一个新的 Promise 对象
- 遍传入的参数,用 Promise.resolve() 将参数”包一层”,使其变成一个 Promise 对象
- 参数所有回调成功才是成功,返回值数组与参数顺序一致
- 参数数组其中一个失败,则触发失败状态,第一个触发失败的 Promise 错误信息作为 Promise.all的错误信息
实现:
function promiseAll (promises){
return new Promise(function(resolve, reject) {
if(!Array.isArray(promises)) {
throw new TypeError('argumenbt must be an array')
}
var resolvedCounter = 0;
var promiseNum = promises.length;
var resolvedResult = [];
for(let i = 0; i < promiseNum; i++) {
Promise.resolve(promises[i]).then(value => {
resolvedCounter++;
resolvedResult[i] = value;
if(resolvedCounter === promiseNum) {
return resolve(resolvedResult);
}
}, error => {
return reject(error)
})
}
})
}
测试:
// ok
let p1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 1000)
})
let p2 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(2);
}, 2000)
})
let p3 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(3);
}, 3000)
})
promiseAll([p1, p2, p3]).then(res => {
console.log(res); // [1, 2, 3]
})
// error
let p1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 1000)
})
let p2 = new Promise(function(resolve, reject) {
setTimeout(function() {
reject(2);
}, 2000)
})
let p3 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(3);
}, 3000)
})
promiseAll([p1, p2, p3]).catch(err => {
console.log(err) // 2
})
Promise.resolve
Promsie.resolve(value) 可以将任何值转成值为 value 状态是 fulfilled 的 Promise,但如果传入的值本身是 Promise 则会原样返回它。
Promise.resolve = function(value) {
// 如果是 Promsie,则直接输出它
if(value instanceof Promise){
return value
}
return new Promise(resolve => resolve(value))
}
Promise.reject
和 Promise.resolve() 类似,Promise.reject() 会实例化一个 rejected 状态的 Promise。但与 Promise.resolve() 不同的是,如果给 Promise.reject() 传递一个 Promise 对象,则这个对象会成为新 Promise 的值。
Promise.reject = function(reason) {
return new Promise((resolve, reject) => reject(reason))
}
Promise.all
Promise.all 的规则是这样的:
- 传入的所有 Promsie 都是 fulfilled,则返回由他们的值组成的,状态为 fulfilled 的新 Promise;
- 只要有一个 Promise 是 rejected,则返回 rejected 状态的新 Promsie,且它的值是第一个 rejected 的 Promise 的值;
- 只要有一个 Promise 是 pending,则返回一个 pending 状态的新 Promise;
/**
* Promise.all Promise进行并行处理
* 参数: promise对象组成的数组作为参数
* 返回值: 返回一个Promise实例
* 当这个数组里的所有promise对象全部进入FulFilled状态的时候,才会resolve。
*/
Promise.all = function(promises) {
return new Promise((resolve, reject) => {
let values = []
let count = 0
promises.forEach((promise, index) => {
promise.then(value => {
console.log('value:', value, 'index:', index)
values[index] = value
count++
if (count === promises.length) {
resolve(values)
}
}, reject)
})
})
}
// or
function PromiseAll(promises){
return new Promise((resolve, reject)=>{
if(!Array.isArray(promises)){
throw new TypeError("promises must be an array")
}
let result = []
let count = 0
promises.forEach((promise, index) => {
promise.then((res)=>{
result[index] = res
count++
count === promises.length && resolve(result)
}, (err)=>{
reject(err)
})
})
})
}
Promise.race
Promise.race 会返回一个由所有可迭代实例中第一个 fulfilled 或 rejected 的实例包装后的新实例。
/**
* Promise.race
* 参数: 接收 promise对象组成的数组作为参数
* 返回值: 返回一个Promise实例
* 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理(取决于哪一个更快)
*/
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(resolve, reject);
});
});
}
// or
Promise.race = function(promiseArr) {
return new Promise((resolve, reject) => {
promiseArr.forEach(p => {
Promise.resolve(p).then(val => {
resolve(val)
}, err => {
rejecte(err)
})
})
})
}
Promise.allSettled
Promise.allSettled 的规则是这样:
- 所有 Promise 的状态都变化了,那么新返回一个状态是 fulfilled 的 Promise,且它的值是一个数组,数组的每项由所有 Promise 的值和状态组成的对象;
- 如果有一个是 pending 的 Promise,则返回一个状态是 pending 的新实例;
Promise.allSettled = function(promiseArr) {
let result = []
return new Promise((resolve, reject) => {
promiseArr.forEach((p, i) => {
Promise.resolve(p).then(val => {
result.push({
status: 'fulfilled',
value: val
})
if (result.length === promiseArr.length) {
resolve(result)
}
}, err => {
result.push({
status: 'rejected',
reason: err
})
if (result.length === promiseArr.length) {
resolve(result)
}
})
})
})
}
Promise.any
Promise.any 的规则是这样:
- 空数组或者所有 Promise 都是 rejected,则返回状态是 rejected 的新 Promsie,且值为 AggregateError 的错误;
- 只要有一个是 fulfilled 状态的,则返回第一个是 fulfilled 的新实例;
- 其他情况都会返回一个 pending 的新实例;
Promise.any = function(promiseArr) {
let index = 0
return new Promise((resolve, reject) => {
if (promiseArr.length === 0) return
promiseArr.forEach((p, i) => {
Promise.resolve(p).then(val => {
resolve(val)
}, err => {
index++
if (index === promiseArr.length) {
reject(new AggregateError('All promises were rejected'))
}
})
})
})
}
Promise.finally
接收一个回调函数, 但无参数接收 无论成功失败状态, 都会执行finally
Promise.prototype.finally = function (callback) {
let P = this.constructor; // P===Promise
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
// or
Promise.prototype.finally = function (cb) {
return this.then(function (value) {
return Promise.resolve(cb()).then(function () {
return value
})
}, function (err) {
return Promise.resolve(cb()).then(function () {
throw err
})
})
}
await 实现
实现
function run(gen) {
return new Promise((resolve, reject) => {
const g = gen();
function _next(value) {
let res; // 存储结果
try {
res = g.next(value);
} catch (error) {
reject(error);
}
if (res.deno) {
// 执行结束了
return resolve(res.value); // 结束
}
Promise.resolve(res.value).then(
(newVal) => {
_next(newVal);
},
(err) => g.throw(err)
); // 不然给人家自己处理错误
}
_next();
});
}
function* myGenerator() {
try {
const val1 = yield Promise.resolve('这是值1');
console.log(val1);
const val2 = yield '这是值2';
console.log(val2);
yield Promise.reject('开始产生错误');
// 不执行了
const val3 = yield '这是值3';
console.log(val3);
} catch (error) {
console.log('错误打印', error);
}
}
run(myGenerator);
手写async /await(generator的语法糖)
前提说明
const getData =
() => new Promise(
resolve => setTimeout(() => resolve("data"), 1000)
)
async function test() {
const data = await getData()
console.log('data: ', data);
const data2 = await getData()
console.log('data2: ', data2);
return 'success'
}
// 这样的一个函数 应该再1秒后打印data 再过一秒打印data2 同时打印success
test().then(res => console.log(res))
思路
function* testG() {
// await被编译成了yield
const data = yield getData()
console.log('data: ', data);
const data2 = yield getData()
console.log('data2: ', data2);
return 'success'
}
我们知道,generator函数是不会自动执行的,每一次调用它的next方法,会停留在下一个yield的位置。
利用这个特性,我们只要编写一个自动执行的函数,就可以让这个generator函数完全实现async函数的功能。
const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000))
var test = asyncToGenerator(
function* testG() {
// await被编译成了yield
const data = yield getData()
console.log('data: ', data);
const data2 = yield getData()
console.log('data2: ', data2);
return 'success'
}
)
test().then(res => console.log(res))
实现
asyncToGenerator接受一个generator函数,返回一个promise, 关键就在于,里面用yield来划分的异步流程,应该如何自动执行。
如果是手动执行
在编写这个函数之前,我们先模拟手动去调用这个generator函数去一步步的把流程走完,有助于后面的思考。
function* testG() {
// await被编译成了yield
const data = yield getData()
console.log('data: ', data);
const data2 = yield getData()
console.log('data2: ', data2);
return 'success'
}
我们先调用testG生成一个迭代器
// 返回了一个迭代器
var gen = testG()
然后开始执行第一次next
// 第一次调用next 停留在第一个yield的位置
// 返回的promise里 包含了data需要的数据
var dataPromise = gen.next()
这段代码要切割成左右两部分来看,第一次调用next,其实只是停留在了yield getData()这里,
data的值并没有被确定。
那么什么时候data的值会被确定呢?
下一次调用next的时候,传的参数会被作为上一个yield前面接受的值
也就是说,我们再次调用gen.next('这个参数才会被赋给data变量')的时候
data的值才会被确定为'这个参数才会被赋给data变量
gen.next('这个参数才会被赋给data变量')
// 然后这里的data才有值
const data = yield getData()
// 然后打印出data
console.log('data: ', data);
// 然后继续走到下一个yield
const data2 = yield getData()
然后往下执行,直到遇到下一个yield,继续这样的流程...
这是generator函数设计的一个比较难理解的点,但是为了实现我们的目标,还是得去学习它~
借助这个特性,如果我们这样去控制yield的流程,是不是就能实现异步串行了?
function* testG() {
// await被编译成了yield
const data = yield getData()
console.log('data: ', data);
const data2 = yield getData()
console.log('data2: ', data2);
return 'success'
}
var gen = testG()
var dataPromise = gen.next()
dataPromise.then((value1) => {
// data1的value被拿到了 继续调用next并且传递给data
var data2Promise = gen.next(value1)
// console.log('data: ', data);
// 此时就会打印出data
data2Promise.value.then((value2) => {
// data2的value拿到了 继续调用next并且传递value2
gen.next(value2)
// console.log('data2: ', data2);
// 此时就会打印出data2
})
})
手写实现
// 正式版
function asyncToGenerator(generatorFunc) {
return function() {
const gen = generatorFunc.apply(this, arguments)
return new Promise((resolve, reject) => {
function step(key, arg) {
let generatorResult
try {
generatorResult = gen[key](arg "key")
} catch (error) {
return reject(error)
}
const { value, done } = generatorResult
if (done) {
return resolve(value)
} else {
return Promise.resolve(value).then(val => step('next', val), err => step('throw', err))
}
}
step("next")
})
}
}
// 导演剪辑版
function asyncToGenerator(generatorFunc) {
// 返回的是一个新的函数
return function() {
// 先调用generator函数 生成迭代器
// 对应 var gen = testG()
const gen = generatorFunc.apply(this, arguments)
// 返回一个promise 因为外部是用.then的方式 或者await的方式去使用这个函数的返回值的
// var test = asyncToGenerator(testG)
// test().then(res => console.log(res))
return new Promise((resolve, reject) => {
// 内部定义一个step函数 用来一步一步的跨过yield的阻碍
// key有next和throw两种取值,分别对应了gen的next和throw方法
// arg参数则是用来把promise resolve出来的值交给下一个yield
function step(key, arg) {
let generatorResult
// 这个方法需要包裹在try catch中
// 如果报错了 就把promise给reject掉 外部通过.catch可以获取到错误
try {
generatorResult = gen[key](arg)
} catch (error) {
return reject(error)
}
// gen.next() 得到的结果是一个 { value, done } 的结构
const { value, done } = generatorResult
if (done) {
// 如果已经完成了 就直接resolve这个promise
// 这个done是在最后一次调用next后才会为true
// 以本文的例子来说 此时的结果是 { done: true, value: 'success' }
// 这个value也就是generator函数最后的返回值
return resolve(value)
} else {
// 除了最后结束的时候外,每次调用gen.next()
// 其实是返回 { value: Promise, done: false } 的结构,
// 这里要注意的是Promise.resolve可以接受一个promise为参数
// 并且这个promise参数被resolve的时候,这个then才会被调用
return Promise.resolve(
// 这个value对应的是yield后面的promise
value
).then(
// value这个promise被resove的时候,就会执行next
// 并且只要done不是true的时候 就会递归的往下解开promise
// 对应gen.next().value.then(value => {
// gen.next(value).value.then(value2 => {
// gen.next()
//
// // 此时done为true了 整个promise被resolve了
// // 最外部的test().then(res => console.log(res))的then就开始执行了
// })
// })
function onResolve(val) {
step("next", val)
},
// 如果promise被reject了 就再次进入step函数
// 不同的是,这次的try catch中调用的是gen.throw(err)
// 那么自然就被catch到 然后把promise给reject掉啦
function onReject(err) {
step("throw", err)
},
)
}
}
step("next")
})
}
}
实现限制并发的Promise调度器
JS实现一个带并发限制的异步调度器Scheduler, 保证同时运行的任务最多有两个
## 题目
```js
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.limit = limit
this.count = 0
}
add(time, order) {
const promiseCreator = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(order)
resolve()
}, time)
})
}
this.queue.push(promiseCreator)
}
taskStart() {
for(let i = 0; i < this.limit; i++) {
this.request()
}
}
request() {
if (!this.queue.length || this.count >= this.limit) return
this.count++
this.queue.shift()().then(() => {
this.count--
this.request()
})
}
}
// 测试
const scheduler = new Scheduler(2);
const addTask = (time, order) => {
scheduler.add(time, order);
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
scheduler.taskStart();
```