vue2.x 无缝升级到 vue3.x
背景
- vue3做了很多优化,比如说diff算法(最长上升子序列),数据劫持优化使用了proxy,解决了之前数组和对象添加新属性的更新问题,更小的体积;编译优化:靶向更新,提升(变量提升,静态字符串,公共样式);语法优化:compositionAPI
- 可以参考:https://juejin.cn/post/6903012926660018183#heading-7
- 未来 vue2项目需要升级成 vue3版本的,包括nuxt,虽然 Vue2团队尽可能的减少了破坏性的更新,还提供了一份细致的迁移指南,大部分是体力活,有的改起来稍微有点麻烦,比如自定义指令生命周期的更名,以及传入参数的一些细微变化。
思路:vue2 => AST => 经过一个据迁移指南自己根写的插件 =>vue3
工具:gogocode-plugin-vue
阿里妈妈的新工具 GoGoCode的内置工具,GoGoCode,一个 AST处理工具
使用
全局安装
npm install gogocode-cli -g
迁移源文件: 进入需要升级的vue目录
gogocode -s ./src(原文件的文件目录) -t gogocode-plugin-vue -o ./src-out(输出的文件目录)
//如果两个文件目录名字相同,转换插件会覆盖你的代码,所以请一定先备份
- 依赖升级(升级package.json中的vue/vuex/vue-router/Vue编译工具)
如果是老版本 vue-cli生成的项目,需要自行升级vue-cli 确保vue3项目能成功被构建 vue-cli4.5.0及以上
gogocode -s package.json -t gogocode-plugin-vue -o package.json
需要关注的地方:window.$vueApp = Vue.createApp(App) 需要提到最前面
- 一些依赖于vue2开发的组件库也推出了vue3版本,如果API发生了变化,需要自己手动升级,(这得是个麻烦事),
- 做好人工对比和测试,以免有没有覆盖的写法
- 升级依赖很坑!!!!! 升级webpack4后一堆不兼容,5也是。html-webpack-plugin都不兼容,尤其是babel插件,需要用babel-upgrade 升级,babel-plugin-transform-vue-jsx也要升级到4.0.1,因为依赖了@babel/plugin-syntax-jsx: 参考:https://github.com/vuejs/babel-plugin-transform-vue-jsx/blob/master/package.json
- 各种路由,各种vue找不到,综合管理后台放弃!!!
- element-plus 也有不向下兼容的,比如说时间控件:https://github.com/element-plus/element-plus/issues/162
Nuxt 3情况
支持 webpack5 和 vite
PostCss 8 :https://www.postcss.com.cn/
- 是一个用 JavaScript 工具和插件转换 CSS 代码的工具
- 自动添加浏览器前缀 : 插件Autoprefixer
- 帮你将最新的 CSS 语法转换成大多数浏览器都能理解的语法,并根据你的目标浏览器或运行时环境来确定你需要的 polyfills(),插件postcss-cssnext
- 自动把px转为rem 插件 :postcss-pxtorem
- CSS 模块 能让你你永远不用担心命名太大众化而造成冲突,只要用最有意义的名字就行了。需要详细学习 ```css / style.css / .className { color: green; }
import styles from “./style.css”; // import { className } from “./style.css”;
element.innerHTML = ‘
- 通过使用[stylelint](https://stylelint.io/) 强化一致性约束并避免样式表中的错误。stylelint 是一个现代化 CSS 代码检查工具。它支持最新的 CSS 语法,也包括类似 CSS 的语法,例如 SCSS
- 处理流程图如下:参考:[https://www.jianshu.com/p/9a9048bc8978](https://www.jianshu.com/p/9a9048bc8978)
![](https://cdn.nlark.com/yuque/0/2021/jpeg/225247/1625127912545-3759a436-c90d-40e9-bb3a-cc61e373398d.jpeg)
<a name="FOCjX"></a>
#### ESBuild
<a name="O9jX9"></a>
#### 用ts重写了
<a name="oDEbM"></a>
#### 用vue3渲染
<a name="xWC6C"></a>
#### 模块化工具
<a name="HE6DX"></a>
#### 新的渲染引擎:Nitro 什么鬼??
<a name="G5bWC"></a>
#### 入口文件app.vue
<a name="POB0l"></a>
#### 可选的page文件夹
<a name="OW9fZ"></a>
#### Alpha 版本2021第一季度开源,Beta 版本第二季度开源。。。好像被骗了,并没有找到
来自:[https://nuxt.slides.com/atinux/nuxt-3-in-action](https://nuxt.slides.com/atinux/nuxt-3-in-action)<br />[
](https://www.jianshu.com/p/9a9048bc8978)
<a name="t1jwj"></a>
## reduce用法大全
<a name="GRJ6F"></a>
### 1、语法
- 接收2个参数,第一个是回调函数(必选),第二个参数是初始值initialValue(可选)
- 回调函数接收4个参数(累计器,当前值,当前索引,源数组)
- ⚠️初始值initialValue 可以是任意类型,如果没有提供initialValue,从索引1开始执行callback;如果提供了initialValue,从索引0开始执行;
- 它的执行就像一个贪吃蛇,蛇每吃一个豆子,豆子将会变成蛇身的一部分,蛇再去吃下一个豆子。![微信图片_20210809114803.png](https://cdn.nlark.com/yuque/0/2021/png/225247/1628480959729-ff2b1259-008b-4d27-bb0e-b9771bf421e8.png#clientId=ufed67d6c-c4c6-4&from=ui&id=uab1ac4a3&margin=%5Bobject%20Object%5D&name=%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20210809114803.png&originHeight=340&originWidth=500&originalType=binary&ratio=1&size=165271&status=done&style=none&taskId=u23ffed75-34c5-4905-9a7b-57f59dffcf7)
```javascript
//不带初始值
[1,2,3,4].reduce((acc, cur) => {
return acc + cur
})
//带初始值
[1,2,3,4].reduce((acc, cur) => {
return acc + cur
}, 10)
2、重塑
reduce ->map
map 接受一个回调函数,参数为(当前项,索引,原数组),返回一个新数组,并且数组长度不变
const testArr = [1,2,3,4]
Array.prototype.reduceMap = function(callback){
//this拿到当前需要操作的数组
return this.reduce((acc,cur,index,array)=>{
const item = callback(cur,index,array)
acc.push(item)
return acc
},[])
}
testArr.reduceMap((item, index) => {
return item + index
})
reduce -> forEach
forEach接收两个函数作为参数,第一个参数回调函数,接受四个参数(当前项,索引,原数组);第二个参数thisArg为当执行回调函数 callback 时,用作 this 的值
- 当指定了thisArg时,每次callback调用时,this都会指向 thisArg 参数;如果省略或者为null\undefined,this指向全局对象;如果回调函数是箭头函数,则此参数不起作用(箭头函数内部绑定了this值)
- forEach没有返回值,不可以链式调用
forEach不能中止,除非抛出异常
const testArr = [1,2,3,4]
Array.prototype.reduceForEach = function(callback){
this.reduce((acc,cur,index,array)=>{
callback(cur,index,array)
},[])
}
testArr.reduceForEach((item, index, array) => {
console.log(item, index)
})
reduce -> filter
接收一个回调函数,参数返回true则返回当前项,反之不返回。回调函数参数(当前项,index,array)
const testArr = [1,2,3,4]
Array.prototype.reduceFilter = function(callback){
return this.reduce((acc,cur,index,array)=>{
if(callback(cur,index,array)){
acc.push(cur)
}
return acc
},[])
}
testArr.reduceFilter(item => item % 2 == 0)
reduce -> find
参数一为callback(当前元素,index,array)
- 参数二为thisArg,执行回调时用作this 的对象。可选
返回第一个满足callback 的元素的值
const testArr = [1,2,3,4]
const testObj = [{a:1},{a:2},{a:3},{a:4},{a:5}]
Array.prototype.reduceFind = function(callback){
return this.reduce((acc,cur,index,array)=>{
//如果找到了,并且acc.length ===0(代表找到的第一个),此时循环依旧进行,
//只是不再进行操作
if(callback(cur,index,array)){
if(acc instanceof Array && acc.length ===0){
acc = cur
}
}
//如果都循环到最后一项了都没找到(acc.length==0),说明需要返回undefined
if((index === array.length -1) && acc instanceof Array && acc.length == 0){
acc = undefined
}
return acc
},[])
testArr.reduceFind(item => item % 2 == 0) // 2
testObj.reduceFind(item => item.a % 2 == 0) // {a: 2}
testObj.reduceFind(item => item.a % 9 == 0) // undefined
}
//这个方法 ,如果找到了第一个符合条件的,但是循环并没有停止,只是不会处理结果,优化点?
使用
二维数组转一维数组
备注:可以使用flat,深度可以自定义,flatMap了解 ```javascript const testArr = [[1,2], [3,4], [5,6]] testArr.reduce((acc, cur) => { return acc.concat(cur) }, [])
<a name="hcoS2"></a>
#### 计算数组中每个元素出现的个数
```javascript
const testArr = [1, 3, 4, 1, 3, 2, 9, 8, 5, 3, 2, 0, 12, 10]
testArr.reduce((acc, cur) => {
if (!(cur in acc)) {
acc[cur] = 1
} else {
acc[cur] += 1
}
return acc
}, {})
按照属性给数组分类
const bills = [
{ type: 'shop', momey: 223 },
{ type: 'study', momey: 341 },
{ type: 'shop', momey: 821 },
{ type: 'transfer', momey: 821 },
{ type: 'study', momey: 821 }
];
bills.reduce((acc, cur) => {
// 如果不存在这个键,则设置它赋值 [] 空数组
if (!acc[cur.type]) {
acc[cur.type] = [];
}
acc[cur.type].push(cur)
return acc
}, {})
数组去重
可以使用Set 和 Array.from()
const testArr = [1,2,2,3,4,4,5,5,5,6,7]
testArr.reduce((acc, cur) => {
if (!(acc.includes(cur))) {
acc.push(cur)
}
return acc
}, [])
求最大值或者最小值
const testArr = [
{ age: 20 },
{ age: 21 },
{ age: 22 }
]
testArr.reduce((acc, cur) => {
if (!acc) {
acc = cur
return acc
}
if (acc.age < cur.age) {
acc = cur
return acc
}
return acc
}, 0)
按照顺序运行Promise(异步函数的串行)
可以运用在下一个异步需要依赖上一个异步的返回值的 情况下
- 没有依赖的情况下用Promise.all ```javascript function runPromiseInSequence(arr,input){ return arr.reduce((promiseChain,currentFunction)=>{ return promiseChain.then(currentFunction) //将下一个Promise作为上一个的then回调 },Promise.resolve(input)) //Promise.resolve(input) ,将初始值input转为Promise } function p1(a) { return new Promise((resolve, reject) => { resolve(a 5); }); } function p2(a) { return new Promise((resolve, reject) => { resolve(a 2); }); } function f3(a) { return a 3; } function p4(a) { return new Promise((resolve, reject) => { resolve(a 4); }); } const promiseArr = [p1, p2, f3, p4]; runPromiseInSequence(promiseArr, 10) .then(console.log); // 1200
//then回调的处理
<a name="IHGMz"></a>
#### 功能型函数管道
```javascript
const double = x => x + x;
const triple = x => 3 * x;
const quadruple = x => 4 * x;
// Function composition enabling pipe functionality
const pipe = (...functions) => input => functions.reduce(
(acc, fn) => fn(acc),
input
);
// Composed functions for multiplication of specific values
const multiply6 = pipe(double, triple);
const multiply9 = pipe(triple, triple);
const multiply16 = pipe(quadruple, quadruple);
const multiply24 = pipe(double, triple, quadruple);
// Usage
multiply6(6); // 36
multiply9(9); // 81
multiply16(16); // 256
multiply24(10); // 240
- koa的源码中,有一个only模块,整个模块就一个简单的返回reduce方法操作的对象,新建并返回一个obj对象中存在的keys的object对象。
参考:https://segmentfault.com/a/1190000010731933var only = function(obj, keys){
obj = obj || {};
if ('string' == typeof keys) keys = keys.split(/ +/);
return keys.reduce(function(ret, key){
if (null == obj[key]) return ret;
ret[key] = obj[key];
return ret;
}, {});
};
var a = {
env : 'development',
proxy : false,
subdomainOffset : 2
}
only(a,['env','proxy']) // {env:'development',proxy : false}
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
chrome调试不完全指南
- 待补充,跟性能优化有关系,比如说内存占用啥的,以及浏览器原理,v8引擎等
- object 的 delete的坑,了解对象在v8中的存储方式,transition tree ,快属性和慢属性,如果你对一个对象的属性进行 delete 操作,就会导致对象的存储方式退化到字典模式(慢属性模式)。相对于之前的快属性模式,这种存储方式更加消耗内存
参考:https://mp.weixin.qq.com/s/teWRsE0_eOF0-gXl5vCHiw
https://mp.weixin.qq.com/s/oPDb_VuwkA5XLaHKef7uZA
https://mp.weixin.qq.com/s/Ng-NCPOfOHTVnF0OvARzEw
一步步实现一个Promise
平常用promise的时候, 是通过new关键字来new Promise(), 所以咱们应该用构造函数或者class来实现. 都2021年了, 咱们就用class来实现一下吧.
class MPromise {
constructor() {
}
}
定义三种状态类型
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
设置初始状态
class MPromise {
constructor() {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
}
}
resolve 和 reject 方法
- 根据刚才的规范, 这两个方法是要更改status的, 从pending改到fulfilled/rejected.
- 注意两个函数的入参分别是value 和 reason.
class MPromise {
constructor() {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
}
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
}
}
}
- 是不是发现咱们的promise少了入参, 咱们来加一下
- 入参是一个函数, 函数接收resolve和reject两个参数.
- 注意在初始化promise的时候, 就要执行这个函数, 并且有任何报错都要通过reject抛出去
class MPromise {
constructor(fn) {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
try {
fn(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
}
}
}
- 接下来来实现一下关键的then方法
- then接收两个参数, onFulfilled 和 onRejected
then(onFulfilled, onRejected) {}
- 检查并处理参数, 之前提到的如果不是function, 就忽略. 这个忽略指的是原样返回value或者reason.
isFunction(param) {
return typeof param === 'function';
}
then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason
};
}
- 根据当前promise的状态, 调用不同的函数
then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
switch (this.status) {
case FULFILLED: {
fulFilledFn(this.value);
break;
}
case REJECTED: {
rejectedFn(this.reason);
break;
}
}
}
- 这个时候有的同学要问了, 你这样写, 是在then函数被调用的瞬间就会执行. 那这时候如果status还没变成fulfilled或者rejected怎么办, 很有可能还是pending的.
- 那么我们首先要拿到所有的回调, 然后才能在某个时机去执行他. 新建两个数组, 来分别存储成功和失败的回调, 调用then的时候, 如果还是pending就存入数组.
then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
switch (this.status) {
case FULFILLED: {
fulFilledFn(this.value);
break;
}
case REJECTED: {
rejectedFn(this.reason);
break;
}
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
this.REJECTED_CALLBACK_LIST.push(realOnRejected);
break;
}
}
}
2. 在status发生变化的时候, 就执行所有的回调. 这里咱们用一下es6的getter和setter. 这样更符合语义, 当status改变时, 去做什么事情. (当然也可以顺序执行, 在给status赋值后, 下面再加一行forEach)
get status() {
return this._status;
}
set status(newStatus) {
switch (newStatus) {
case FULFILLED: {
this.FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value);
});
break;
}
case REJECTED: {
this.REJECTED_CALLBACK_LIST.forEach(callback => {
callback(this.reason);
});
break;
}
}
}
then的返回值
这块内容比较多, 所以单拿出来了
7.1 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e。(这样的话, 我们就需要手动catch代码,遇到报错就reject)
7.2 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
7.3 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。
需要注意的是,如果promise1的onRejected执行成功了,promise2应该被resolve
7.4 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行resolvePromise方法then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
const fulFilledFnWithCatch = (resolve, reject) => {
try {
fulFilledFn(this.value);
} catch (e) {
reject(e)
}
};
const rejectedFnWithCatch = (resolve, reject) => {
try {
rejectedFn(this.reason);
} catch (e) {
reject(e);
}
}
switch (this.status) {
case FULFILLED: {
return new MPromise(fulFilledFnWithCatch);
}
case REJECTED: {
return new MPromise(rejectedFnWithCatch);
}
case PENDING: {
return new MPromise((resolve, reject) => {
this.FULFILLED_CALLBACK_LIST.push(() => fulFilledFnWithCatch(resolve, reject));
this.REJECTED_CALLBACK_LIST.push(() => rejectedFnWithCatch(resolve, reject));
});
}
}
}
const fulFilledFnWithCatch = (resolve, reject) => {
try {
fulFilledFn(this.value);
resolve(this.value);
} catch (e) {
reject(e)
}
};
const rejectedFnWithCatch = (resolve, reject) => {
try {
rejectedFn(this.reason);
if (this.isFunction(onRejected)) {
resolve();
}
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
const fulFilledFnWithCatch = (resolve, reject, newPromise) => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
const x = fulFilledFn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e)
}
};
const rejectedFnWithCatch = (resolve, reject, newPromise) => {
try {
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
const x = rejectedFn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
}
switch (this.status) {
case FULFILLED: {
const newPromise = new MPromise((resolve, reject) => fulFilledFnWithCatch(resolve, reject, newPromise));
return newPromise;
}
case REJECTED: {
const newPromise = new MPromise((resolve, reject) => rejectedFnWithCatch(resolve, reject, newPromise));
return newPromise;
}
case PENDING: {
const newPromise = new MPromise((resolve, reject) => {
this.FULFILLED_CALLBACK_LIST.push(() => fulFilledFnWithCatch(resolve, reject, newPromise));
this.REJECTED_CALLBACK_LIST.push(() => rejectedFnWithCatch(resolve, reject, newPromise));
});
return newPromise;
}
}
}
resolvePromise
resolvePromise(newPromise, x, resolve, reject) {
// 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
// 这是为了防止死循环
if (newPromise === x) {
return reject(new TypeError('The promise and the return value are the same'));
}
if (x instanceof MPromise) {
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
// 这个if跟下面判断then然后拿到执行其实重复了,可有可无
x.then((y) => {
resolvePromise(newPromise, y, resolve, reject);
}, reject);
} else if (typeof x === 'object' || this.isFunction(x)) {
// 如果 x 为对象或者函数
// 这个坑是跑测试的时候发现的,如果x是null,应该直接resolve
if (x === null) {
return resolve(x);
}
let then = null;
try {
// 把 x.then 赋值给 then
then = x.then;
} catch (error) {
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(error);
}
// 如果 then 是函数
if (this.isFunction(then)) {
let called = false;
// 将 x 作为函数的作用域 this 调用之
// 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise
// 名字重名了,我直接用匿名函数了
try {
then.call(
x,
// 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise
(y) => {
// 如果 resolvePromise 和 rejectPromise 均被调用,
// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
// 实现这条需要前面加一个变量called
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
(r) => {
if (called) return;
called = true;
reject(r);
});
} catch (error) {
// 如果调用 then 方法抛出了异常 e:
// 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
if (called) return;
// 否则以 e 为据因拒绝 promise
reject(error);
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x);
}
} else {
// 如果 x 不为对象或者函数,以 x 为参数执行 promise
resolve(x);
}
}
onFulfilled 和 onRejected 是微任务
咱们可以用queueMicrotask包裹执行函数then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
const fulFilledFnWithCatch = (resolve, reject, newPromise) => {
queueMicrotask(() => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
const x = fulFilledFn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e)
}
})
};
const rejectedFnWithCatch = (resolve, reject, newPromise) => {
queueMicrotask(() => {
try {
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
const x = rejectedFn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
})
}
switch (this.status) {
case FULFILLED: {
const newPromise = new MPromise((resolve, reject) => fulFilledFnWithCatch(resolve, reject, newPromise));
return newPromise;
}
case REJECTED: {
const newPromise = new MPromise((resolve, reject) => rejectedFnWithCatch(resolve, reject, newPromise));
return newPromise;
}
case PENDING: {
const newPromise = new MPromise((resolve, reject) => {
this.FULFILLED_CALLBACK_LIST.push(() => fulFilledFnWithCatch(resolve, reject, newPromise));
this.REJECTED_CALLBACK_LIST.push(() => rejectedFnWithCatch(resolve, reject, newPromise));
});
return newPromise;
}
}
}
简单写点代码测试一下
这个时候同学们会发现, 为什么我可以调用.then, 不可以调用.catch呢? 因为我们并没有在类里面声明catch方法 ```javascript const test = new MPromise((resolve, reject) => { setTimeout(() => { resolve(111); }, 1000); }).then(console.log);
console.log(test);
setTimeout(() => { console.log(test);
}, 2000)
11. catch方法
```javascript
catch (onRejected) {
return this.then(null, onRejected);
}
promise.resolve
将现有对象转为Promise对象,如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled。static resolve(param) {
if (param instanceof MyPromise) {
return param;
}
return new MyPromise(function (resolve) {
resolve(param);
});
}
promise.reject
返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。static reject(reason) {
return new MPromise((resolve, reject) => {
reject(reason);
});
}
promise.race
const p = Promise.race([p1, p2, p3]);
该方法是将多个 Promise 实例,包装成一个新的 Promise 实例。
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
写段测试代码
```javascript static race(promiseList) { return new MPromise((resolve, reject) => { const length = promiseList.length;if (length === 0) {
return resolve();
} else {
for (let i = 0; i < length; i++) {
MPromise.resolve(promiseList[i]).then(
(value) => {
return resolve(value);
},
(reason) => {
return reject(reason);
});
}
} });
}
```javascript
const test = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000);
});
const test2 = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 2000);
});
const test3 = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(333);
}, 3000);
});
MPromise.race([test, test2, test3]).then(console.log);