Promise
类式实现
class MyPromise {constructor(executor) {this.state = 'pending'; // resolved rejectedthis.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,rejectif (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 = thisfunction resolve(value) { // 成功的方法if (that.status === 'pending') {that.status = 'resolved'that.value = valuethat.fulfilledCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法}}function reject(value) { //失败的方法if (that.status === 'pending') {that.status = 'rejected'that.value = valuethat.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 = undefinedself.reason = undefinedself.onResolved = []self.onRejected = []function resolve(value) {if (self.status === 'pending') {self.status = 'fulfilled'self.value = valueself.onResolved.forEach(fn => fn())}}function reject(reason) {if (self.status === 'pending') {self.reason = reasonself.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 = thisif (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)})}})}
测试:
// oklet 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]})// errorlet 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 = 0promises.forEach((promise, index) => {promise.then(value => {console.log('value:', value, 'index:', index)values[index] = valuecount++if (count === promises.length) {resolve(values)}}, reject)})})}// orfunction PromiseAll(promises){return new Promise((resolve, reject)=>{if(!Array.isArray(promises)){throw new TypeError("promises must be an array")}let result = []let count = 0promises.forEach((promise, index) => {promise.then((res)=>{result[index] = rescount++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);});});}// orPromise.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 = 0return new Promise((resolve, reject) => {if (promiseArr.length === 0) returnpromiseArr.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===Promisereturn this.then(value => P.resolve(callback()).then(() => value),reason => P.resolve(callback()).then(() => { throw reason }));};// orPromise.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 同时打印successtest().then(res => console.log(res))
思路
function* testG() {// await被编译成了yieldconst 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被编译成了yieldconst 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被编译成了yieldconst 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()// 然后打印出dataconsole.log('data: ', data);// 然后继续走到下一个yieldconst data2 = yield getData()然后往下执行,直到遇到下一个yield,继续这样的流程...这是generator函数设计的一个比较难理解的点,但是为了实现我们的目标,还是得去学习它~借助这个特性,如果我们这样去控制yield的流程,是不是就能实现异步串行了?function* testG() {// await被编译成了yieldconst 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并且传递给datavar data2Promise = gen.next(value1)// console.log('data: ', data);// 此时就会打印出datadata2Promise.value.then((value2) => {// data2的value拿到了 继续调用next并且传递value2gen.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 generatorResulttry {generatorResult = gen[key](arg "key")} catch (error) {return reject(error)}const { value, done } = generatorResultif (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出来的值交给下一个yieldfunction 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 } = generatorResultif (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后面的promisevalue).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, 保证同时运行的任务最多有两个
## 题目```jsaddTask(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 = limitthis.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) returnthis.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();
```
