校验promiseA+规范
此时我们可以安装一个工具来测试是否符合 promiseA+ 规范:promises-aplus-tests
npm i -D promises-aplus-tests
运行命令
promises-aplus-tests myPromise3.js // 文件名// package.json"test": "promises-aplus-tests ./myPromise3.js"
var d = adapter.deferred();TypeError: adapter.deferred is not a function
这时要在 myPromise.js 加入这段代码
MyPromise.defer = MyPromise.deferred = function () {let deferred = {}deferred.promise = new MyPromise((resolve, reject) => {deferred.resolve = resolvedeferred.reject = reject})return deferred}
再次启动即可
实现resolve与reject的静态方法
static resolve(value) {return new MyPromise((resolve,reject)=>{resolve(value)})}static reject(reason){return new MyPromise((resolve,reject)=>{reject(reason)})}
同时要对 resolve进行改造,否则会忽略异步中的新的Promise
const resolve = (value) => {// 校验一下是否为一个MyPromise,是的话就继续走then,否则会直接把异步Promise执行掉if (value instanceof MyPromise) {value.then((res) => {resolve(res)}, reject)return}if (this.state === "PENDING") {this.state = FULFILLED;this.value = value// 执行等待事件this.onFulfilledCallbacks.forEach(item => {item()})}}
实现promise.all
原理:传入一个数组,数组里面的每一个Promise都成功了,才会成功,返回一个结果为数组,数组里的每一项则是对应的Promise的成功结果;若有其中一个失败,则会失败,用catch捕获其中的报错信息
static all(promiseArr) {
let resArr = [],
idx = 0;
return new MyPromise((resolve, reject) => {
promiseArr.map((promise, index) => {
if (isPromise(promise)) {
promise.then(res => {
(fomatResArr(res, index, resolve))
}, reject)
} else {
fomatResArr(res, index, resolve)
}
})
})
function isPromise(promise) {
if ((typeof promise === "object" && typeof promise !== null) || typeof promise === "function") {
let then = promise.then
return typeof then === "function"
}
}
function fomatResArr(res, index, resolve) {
resArr[index] = res;
if (++idx === promiseArr.length) {
resolve(resArr)
}
}
}
实现Promise.allSettled
allSettled与all的区别大概有两点
1.不管promise的状态成功与否,都会返回到最终结果上
2.如果传进去的不是一个数组或者可迭代对象,会报错的
所以加一个isIterable去判断是否可迭代
function isIterable(value) {
return value !== null && value !== undefined && typeof value[Symbol.iterator] === 'function'
}
static allSettled(promiseArr) {
let resArr = [],
idx = 0;
if (!isIterable(promiseArr)) {
throw new TypeError(promiseArr + 'is not iterable')
}
return new MyPromise((resolve, reject) => {
if (promiseArr.length === 0) {
resolve([])
}
promiseArr.map((promise, index) => {
if (isPromise(promise)) {
promise.then((value) => {
formatResArr("fulfilled", value, index, resolve)
}, (reason) => {
formatResArr("rejected", reason, index, resolve)
})
} else {
formatResArr("fulfilled", value, index, resolve)
}
})
function formatResArr(status, value, index, resolve) {
switch (status) {
case "fulfilled":
resArr[index] = {
status,
value
};
break;
case "rejected":
resArr[index] = {
status,
reason: value
};
break
}
if (++idx === promiseArr.length) {
resolve(resArr)
}
}
})
}
实现Promise.race与finally
race:谁先有结果,就拿谁的结果
static race(promiseArr) {
return new MyPromise((resolve, reject) => {
promiseArr.map((promise) => {
if (isPromise(promise)) {
// 谁快就谁先改状态,就返回谁
promise.then(resolve, reject)
} else {
resolve(promise)
}
})
})
}
finally:先来看几个例子
// 外面是成功
Promise.resolve("promise resolve").finally(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("new Promise")// 都成功,取外面,promise resolve
reject("new Promise reject") // // 里面失败,取里面 new Promise reject
}, 1000)
})
}).then(res => {
console.log("res:", res);
}).catch(err => {
console.log("err:", err);
})
// 外面是失败
Promise.reject("promise reject").finally(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("new Promise resolve") // 外面失败,里面成功,取外面 promise reject
reject("new Promise reject") // // 都失败,取里面 new Promise reject
}, 1000)
})
}).then(res => {
console.log("res:", res);
}).catch(err => {
console.log("err:", err);
})
1.无论外面的Promise成功还是失败,都要走,并且回调不带参数
2.正常走finally之后then或者catch
3.如果finally内部有Promise并且有延时处理,整个finally会等待
4.如果两个都是成功,取外面的结果
5.如果外面是成功,里面是失败,取里面的结果(失败)
6.如果外面是失败,里面是成功,取外面的结果(失败)
7.如果外面是失败,里面是失败,去里面的结果(失败)
8.如果外面是成功,里面是成功,取外面的结果(成功)
总结:只有里面失败了就会失败,并取里面的结果,只有都成功的时候才会取外面成功的结果
// finally实现
finally(finallyCallback) {
return this.then(
(value) => {
let p = MyPromise.resolve(finallyCallback()).then((res) => {
return value
})
return p
},
(reason) => {
return MyPromise.resolve(finallyCallback()).then(() => {
throw reason
})
})
}
实现promisify与promisifyAll
什么是promisify:将一个函数promise化,使之可以进行.then操作
const fs = require('fs')
fs.readFile("./data/user.json", "utf-8", function (err, data) {
if (err) {
console.log(err);
return
}
console.log(data);
})
// 当我们需要把readFile变成异步时例如,则需要promiseify
fs.readFile("./data/user.json", "utf-8").then(res => {
console.log(res);
})
工具实现:blueBird或者node自带的uitl都带有promisify的方法
const readFile = blueBird.promisify(fs.readFile)
const util = require('util')
const readFile = util.promisify(fs.readFile)
手写实现
promisify(fn) {
return function (...arg) {
return new Promise((resolve, reject) => {
// 这里主要因为fs的函数一般都是这种形式
fn(...arg, (err, data) => {
if (err) {
return reject(err)
}
resolve(data)
})
})
}
}
// 就是将一个对象里的所有函数都变成promise
promisifyAll(fns) {
Object.keys(fns).map((fnName) => {
if (typeof fns[fnName] === "function") {
fns[fnName + 'Async'] = this.promisify(fns[fnName])
}
})
return fns
}
