当前位置: 首页 > news >正文

Promise详解

目录

      • 一、前言:为什么会出现Promise?
      • 二、Promise是什么?
        • 2.1 Promise的初体验
      • 三、使用Promise的好处?
        • 3.1 指定回调函数的方式更加灵活
        • 3.2 可以解决回调地狱问题,支持链式调用
      • 四、Promise实例对象的两个属性
      • 五、resolve函数以及reject函数
      • 六、Promise对象的状态
      • 七、Promise的then方法
      • 八、Promise的链式调用
      • 九、Promise下的几种方法
        • 9.1 Promise.resolve()
        • 9.2 Promise.reject()
        • 9.3 Promise.catch()
        • 9.4 Promise.all()
        • 9.5 Promise.race()
        • 9.6 Promise.allSettled()
        • 9.7 Promise.any()
        • 9.8 Promise.finally()
      • 十、终止Promise链条
      • 十一、几个关键问题
        • 11.1 如何修改 promise 对象状态
        • 11.2 指定多个回调执行情况
        • 11.3 指定回调与改变状态先后顺序问题
        • 11.4 promise.then()返回的新promise的结果状态由什么决定?
        • 11.5 promise如何串联多个操作任务?
        • 11.6 promise的异常穿透
        • 11.7 中断promise链
      • 十二、async和await
        • 12.1 async函数
        • 12.2 await表达式
      • 十三、JS中的宏队列与微队列
      • 十四、Promise常见面试题
      • 十五、手写promise自定义基础结构的搭建
        • 15.1 Promise 的基本结构
        • 15.2 Promise实例拥有两个实例属性
        • 15.3 更改状态三种方式-方法未抽离
        • 15.4 更改状态三种方式-抽离为普通函数
        • 15.5 更改状态三种方式-抽离为箭头函数
        • 15.6 状态只允许更改一次
        • 15.7 then函数调用成功或失败回调函数
        • 15.8 then函数中的回调函数是异步调用的
        • 15.9 then函数返回的是一个Promise实例
        • 15.10 then函数返回的Promise实例状态以及值-未优化
        • 15.11 then函数返回的Promise实例状态以及值-优化封装函数_common
        • 15.12 增加成功与失败回调函数的默认值
        • 15.14 执行器函数常用于处理异步行为
        • 15.15 可以指定多个成功或失败的回调
        • 15.16 catch
        • 15.17 链式调用支持
        • 15.18 异常穿透支持
        • 15.19 中断Promise链
        • 15.20 resolve
        • 15.21 reject
        • 15.22 完成all
        • 15.23 完成race
        • 15.24 class版本实现Promise

一、前言:为什么会出现Promise?

Promise的重要性我认为没有必要多讲,概括起来说就是五个字:必!须!得!掌!握!

而且还要掌握透彻,在实际的使用中,有非常多的应用场景我们不能立即知道应该如何继续往下执行。

最常见的一个场景就是ajax请求,通俗来说,由于网速的不同,可能你得到返回值的时间也是不同的,

这个时候我们就需要等待,结果出来了之后才知道怎么样继续下去。

let xhr = new XMLHttpRequest();
xhr.open('get', 'https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=82294778&appsecret=4PKVFula&city=%E5%8C%97%E4%BA%AC');
xhr.send();
xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {console.log(xhr.responseText)}}
}

在ajax的原生实现中,利用了onreadystatechange事件,当该事件触发并且符合一定条件时,才能拿到想要的数

据,之后才能开始处理数据,这样做看上去并没有什么麻烦,但如果这个时候,我们还需要另外一个ajax请求,这

个新ajax请求的其中一个参数,得从上一个ajax请求中获取,这个时候我们就不得不等待上一个接口请求完成之

后,再请求后一个接口。

let xhr = new XMLHttpRequest();
xhr.open('get', 'https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=82294778&appsecret=4PKVFula&city=%E5%8C%97%E4%BA%AC');
xhr.send();
xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {console.log(xhr.responseText)//伪代码....let xhr = new XMLHttpRequest();xhr.open('get','http://www.xx.com?a'+xhr.responseText);xhr.send();xhr.onreadystatechange = function(){if(xhr.readyState === 4){if(xhr.status>=200 && xhr.status<300){console.log(xhr.responseText)}}}}}
}

当出现第三个ajax(甚至更多)仍然依赖上一个请求时,我们的代码就变成了一场灾难。

这场灾难,往往也被称为回调地狱

因此我们需要一个叫做Promise的东西,来解决这个问题,当然,除了回调地狱之外,还有个非常重要的需求就是

为了代码更加具有可读性和可维护性,我们需要将数据请求与数据处理明确的区分开来

上面的写法,是完全没有区分开,当数据变得复杂时,也许我们自己都无法轻松维护自己的代码了。

这也是模块化过程中,必须要掌握的一个重要技能,请一定重视。

二、Promise是什么?

Promise是异步编程的一种解决方案,比传统的解决方案回调函数更合理、更强大。

ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。

指定回调函数的方式也变得更加灵活易懂,也解决了异步回调地狱的问题

旧方案是单纯使用回调函数,常见的异步操作有:定时器、fs模块、ajax、数据库操作

从语法上说,Promise是一个构造函数;

从功能上说,Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值。

2.1 Promise的初体验

创建promise对象(pending状态)

const p = new Promise(executor);

其中:

executor函数: 执行器 (resolve, reject) => {}

resolve函数: 内部定义成功时我们调用的函数 value => {}

reject函数: 内部定义失败时我们调用的函数 reason => {}

executor会在Promise内部立即同步调用,异步操作在执行器中执行

实例对象调用Promise原型中的then方法来完成对结果的处理

<script>const p = new Promise((resolve, reject) => {//如果咱们公司今年挣钱了,年底就发奖金,否则不发resolve('ok');})console.log(p)p.then(() => {console.log('发奖金')}, () => {console.log('不发奖金')})
</script>

三、使用Promise的好处?

3.1 指定回调函数的方式更加灵活

  1. 旧的:必须在启动异步任务前指定

  2. promise:启动异步任务->返回promise对象->给promise对象绑定回调函数

    (甚至可以在异步任务结束后指定/多个)

3.2 可以解决回调地狱问题,支持链式调用

  1. 什么是回调地狱?

    回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件

  2. 回调地狱的缺点?

    不便于阅读

    不便于异常处理

  3. 解决方案?

    promise链式调用

  4. 终极解决方案?

    async/await

四、Promise实例对象的两个属性

  • PromiseState

    此属性为promise对象的状态属性。

    • fulfilled:成功的状态
    • rejected:失败的状态
    • pending:初始化的状态

    【注】状态只能由pending->fulfilled 或者是 pending->rejected

  • PromiseResult

    此属性为promise对象的结果值(resolve以及reject函数的形参值)

五、resolve函数以及reject函数

  • resolve:修改promise对象的状态,由pending修改到fulfilled;将实参设置到这个属性PromiseResult中。
  • reject:修改promise对象的状态,由pending修改到rejected;将实参设置到这个属性PromiseResult中。

案例1:利用promise来进行读取文件操作

//1.普通文件读取方式
const fs = require('fs');//2.直接利用readfile来进行读取
/* fs.readFile(__dirname + '/data.txt',(err,data)=>{if(err) throw err;console.log(data.toString());
}) *///3.利用promise来实现文件的读取
const p = new Promise((resolve, reject) => {fs.readFile(__dirname + '/data.txt', (err, data) => {if (err) {reject(err);}else{resolve(data);}})
}); p.then(value=>{console.log(value.toString());
},reason=>{console.log(reason);
})

案例2:利用promise进行ajax请求

<body><button>发送ajax请求</button><script>//1.获取DOM元素对象let btn = document.querySelector('button');//2.绑定事件btn.onclick = function(){//3.创建promise实例对象const p = new Promise((resolve,reject)=>{//4.创建ajax实例对象const xhr = new XMLHttpRequest();//5.打开请求xhr.open('get','https://www.yiketianqi.com/free/day?appid=82294778&appsecret=4PKVFula&unescape=1');//6.发送请求xhr.send();//7.利用onreadystatechange事件xhr.onreadystatechange = function(){//8.判断if(xhr.readyState == 4){if(xhr.status == 200){resolve(xhr.responseText);}else{reject(xhr.response);}}}});p.then(value=>{console.log(JSON.parse(value));},reason=>{console.log('获取信息失败');})}</script>
</body>

案例3:利用promise进行数据库操作

const mongoose = require('mongoose');new Promise((resolve, reject) => {mongoose.connect('mongodb://127.0.0.1/project');mongoose.connection.on('open', ()=>{//连接成功的情况resolve();});mongoose.connection.on('error', () => {//连接失败的情况reject();})
}).then(value => {//创建结构const NoteSchema = new mongoose.Schema({title: String,content: String})//创建模型const NoteModel = mongoose.model('notes', NoteSchema);//读取操作NoteModel.find().then(value => {console.log(value);}, reason => {console.log(reason);})
}, reason => {console.log('连接失败');
})

案例4:封装一个函数,作用是读取文件

const fs = require('fs');function ReadFileFun(path){return new Promise((resolve,reject)=>{fs.readFile(path,(err,data)=>{//判断if(err){reject(err)}else{resolve(data);}})});
}ReadFileFun('./data.txt').then(value=>{console.log(value.toString());
},reason=>{console.log(reason);
})

node中的promisify

  • promisify (只能在 NodeJS 环境中使用)
  • promisify 是 util 模块中的一个方法 util 是 nodeJS 的内置模块
  • 作用: 返回一个新的函数, 函数的是 promise 风格的.
const util = require('util');
const fs = require('fs');
//通过 fs.readFile 创建一个新的函数
const mineReadFile = util.promisify(fs.readFile);mineReadFile('./resource/2.html')
.then(value => {console.log(value.toString());
}, reason => {console.log(reason);
})

六、Promise对象的状态

Promise对象通过自身的状态来控制异步操作,Promise实例具有三种状态.

  • 异步操作未完成:pending
  • 异步操作成功:fulfilled
  • 异步操作失败:rejected

这三种的状态的变化途径只有两种

  • 从pending(未完成)到fulfilled(成功)
  • 从pending(未成功)到rejected(失败)

一旦状态发生变化,就凝固了,不会再有新的状态变化,这也是Promise这个名字的由来,它的英语意思"承诺",

一旦承诺生效,就不得再改变了,这也意味着Promise实例的状态变化只可能发生一次。

在Promise对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理Promise的状态变化。

上面的resolve和reject都为一个函数,他们的作用分别是将状态修改为resolved和rejected。

因此,Promise的最终结果只有两种。

异步操作成功,Promise实例传回一个值(value),状态变为fulfilled.
异步操作失败,Promise实例抛出一个错误(error),状态变为rejected

七、Promise的then方法

then:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象

  • 成功的状态:执行第一个回调函数
  • 失败的状态:执行第二个回调函数

promise.then()返回的新promise的结果状态由什么决定?

(1) 简单表达: 由then()指定的回调函数执行的结果决定

(2) 详细表达:

① 如果抛出异常, 新promise变为rejected, reason为抛出的异常

const p = new Promise((resolve,reject)=>{resolve('ok');
});let result = p.then(value=>{throw '错误';
},reason=>{console.log(reason);
});console.log(result);

② 如果返回的是非promise的任意值, 新promise变为fulfilled, PromiseResult为返回的值

const p = new Promise((resolve,reject)=>{resolve('ok');
});let result = p.then(value=>{return 100;
},reason=>{console.log(reason);
});console.log(result);

③ 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果

const p = new Promise((resolve,reject)=>{resolve('ok');
});let result = p.then(value=>{return new Promise((resolve,reject)=>{//resolve('111');reject('error');})
},reason=>{console.log(reason);
});console.log(result);

八、Promise的链式调用

const p = new Promise((resolve,reject)=>{//resolve('ok');reject('error');
});p.then(value=>{console.log(value);
},reason=>{console.log(reason);
}).then(value=>{console.log(value);
},reason=>{console.log(reason);
})

案例:通过promise的链式调用来读取文件

回调地狱的方式:

const fs = require('fs');
fs.readFile('./resource/1.html',(err,data1)=>{if(err) throw err;fs.readFile('./resource/1.html',(err,data2)=>{if(err) throw err;fs.readFile('./resource/1.html',(err,data3)=>{if(err) throw err;console.log(data1 + data2 + data3);})})
})

Promise的形式:

需求:读取resource下三个文件内容,并在控制台合并输出

new Promise((resolve,reject)=>{fs.readFile('./resource/1.html',(err,data)=>{//如果失败 则修改promise对象状态为失败if(err) reject(err);//如果成功 则修改promise对象状态为成功resolve(data);})
}).then(value=>{return new Promise((resolve,reject)=>{fs.readFile('./resource/2.html',(err,data)=>{//失败if(err) reject(err);//成功resolve([value,data]);})})
}).then(value=>{return new Promise((resolve,reject)=>{fs.readFile('./resource/3.html',(err,data)=>{//失败if(err) reject(err);value.push(data);//成功resolve(value);})})
}).then(value=>{console.log(value.join(""));
})

九、Promise下的几种方法

9.1 Promise.resolve()

将一个普通值转化为promise类型的数据

  • 若参数为非promise对象,则返回的结果为成功状态的promise对象
let p1 = Promise.resolve(123);
console.log(p1);
let p2 = Promise.resolve(undefined);
console.log(p2);
  • 若参数为promise对象,参数的状态决定返回结果的状态
let p3 = Promise.resolve(new Promise((resolve,reject)=>{resolve('success');
}));
console.log(p3);let p4 = Promise.resolve(Promise.resolve(Promise.resolve("OK")));
console.log(p4);

9.2 Promise.reject()

返回的结果始终为失败的Promise对象

console.log(Promise.reject(123));
console.log(Promise.reject(Promise.resolve('ok')));

9.3 Promise.catch()

功能是用来指定失败的回调函数

let p = new Promise((resolve,reject)=>{//resolve('success');reject('error');
});p.catch(reason=>{console.log(reason);
});//then方法中不是必须传入两个参数,可以只传递成功时的回调函数
//也可以单独使用catch来指定失败的回调函数//异常(错误)穿透
//当如果有多个需要执行的成功时的回调函数,可以不需要每一次都写失败回调,可以统一最后利用catch
//当如果promise对象的状态为reject的话,会一直向下穿透直到catch方法
p.then(value=>{console.log(value);
}).then(value=>{console.log(value);
}).catch(reason=>{console.log(reason);
})

9.4 Promise.all()

作用:针对于多个Promise的异步任务进行处理

接收的参数:promise数组

返回值:promise对象,状态由promise数组中的对象状态决定

  • 若每个对象状态都为成功,则返回的promise对象状态为成功,

​ 成功的结果值为每个promise对象成功结构值组成的数组

  • 其中一个对象状态为失败,则返回的promise对象状态为失败,

​ 失败的结果值为失败的promise对象的结果值

let p1 = new Promise((resolve, reject) => {resolve('ok');
})
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('oh yeah');
let result = Promise.all([p1, p2, p3])
console.log(result);

当有一个ajax请求,它的参数需要另外2个甚至更多请求都有返回结果之后才能确定,

那么这个时候,就需要用到Promise.all来帮助我们应对这个场景。

Promise.all接收一个Promise对象组成的数组作为参数,

当这个数组所有的Promise对象状态都变成resolved或者rejected的时候,它才会去调用then方法。

//ES6中对Promise.all()的理解以及应用场景
//用于将多个Promise实例,包装成一个新的Promise实例
let p1 = new Promise((resolve,reject)=>{resolve('成功01');
})
let p2 = new Promise((resolve,reject)=>{resolve('成功02');
}).catch(reason=>console.log(reason));
let p3 = new Promise((resolve,reject)=>{resolve('成功03');
})
//参数可以不是数组,但必须是iterator接口
let pAll = Promise.all([p1,p2,p3]);
console.log(pAll)
//pAll的状态是由p1,p2,p3来决定,只有当这三个都为成功,pAll才会为成功,反之,但凡其中一个失败结果就是失败
//这个时候第一个失败的实力的返回值会传递给pAll的回调函数,如果作为参数的实例,自己定义了catch方法,那么它一旦为rejected,是不会触碰到pAll中的catch方法
pAll.then(value=>{console.log(value);
},reason=>{console.log(reason);
})

案例1:模拟请求三个接口中的数据,全部请求成功后获取。

function getUsersList() {return new Promise((resolve, reject) => {//模拟请求用户列表数据setTimeout(() => {resolve('用户列表的数据');}, 1000);})
}
function getBannersList() {return new Promise((resolve, reject) => {//模拟请求用户列表数据setTimeout(() => {resolve('轮播图的数据');}, 2000);})
}
function getVideoList() {return new Promise((resolve, reject) => {//模拟请求用户列表数据setTimeout(() => {resolve('视频列表的数据');}, 3000);})
}
//初始加载的时候
function initLoad() {let all = Promise.all([getUsersList(), getBannersList(), getVideoList()]);//获取成功请求的结果值all.then(value => {console.log(value);})
}
initLoad();

案例2:修改多文件读取代码

const fs = require('fs');
const util = require('util');
const mywriteFile = util.promisify(fs.readFile);
let one = mywriteFile('./resource/1.html');
let two = mywriteFile('./resource/2.html');
let three = mywriteFile('./resource/3.html');
let result = Promise.all([one,two,three]);
result.then(value=>{console.log(value.join(''));
},reason=>{console.log(reason);
})

9.5 Promise.race()

Promise.race race 赛跑的意思

参数: promise 数组

返回结果: promise 对象

状态由『最先改变状态的 promise对象』决定

结果值由 『最先改变状态的 promise对象』决定

let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('ok');}, 2000)
});
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('oh hou');
let result = Promise.race([p1, p2, p3]);
console.log(result);

与Promise.all相似的是,Promise.race都是以一个Promise对象组成的数组作为参数。

不同的是,只要当数组中的其中一个Promsie状态变成resolved或者rejected时,就可以调用.then方法了。

而传递给then方法的值也会有所不同。

<script>//ES6中Promise.race的用法以及使用场景//将多个Promise实例包装成一个新的Promise实例let p1 = new Promise((resolve, rejct) => {setTimeout(() => {resolve('p1成功')}, 2000);})let p2 = new Promise((resolve, rejct) => {setTimeout(() => {resolve('p2成功');}, 1000);}, 1000);//调用const prace = Promise.race([p1, p2]);//Promise.race区别于Promise.all://只要是实例中有一个先改变状态,就会把这个实例的返回值传递给prace的回调函数
</script>
//使用场景:请求超时提示
function request() {return new Promise((resolve, reject) => {setTimeout(() => {resolve('请求成功');}, 4000);})
}
function timeout() {return new Promise((resolve, reject) => {setTimeout(() => {reject('网络不畅,请求超时');}, 3000);});
}
Promise.race([request(), timeout()]).then(value => {console.log(value)
}).catch(reason => {console.log(reason)
})

9.6 Promise.allSettled()

Promise.allSettled()方法,用来确定要一组异步操作是否都结束了(不管成功或失败)。

所以,它的名字叫"Settled",包含了"fufilled"和"rejected"两种情况.

<script>function ajax(url) {return new Promise((resolve, reject) => {let xhr = new XMLHttpRequest();xhr.open('get', url, true);xhr.send();xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {resolve(xhr.responseText);} else {reject(xhr.responseText);}}}})}
//类比Promise下的all方法和allSettled
// Promise.all([ajax('http://www.xiongmaoyouxuan.com/api/tabs'),
// ajax('https://m.maizuo.com/gateway?cityId=110100&k=4770248')
// ]).then(value => {
//     console.log(value)
// }).catch(error => {
//     console.log(error);
// })Promise.allSettled([ajax('http://www.xiongmaoyouxuan.com/api/tabs'),ajax('https://m.maizuo.com/gateway?cityId=110100&k=4770248')]).then(value => {// console.log(value)let successList = value.filter(item => item.status === 'fulfilled');console.log(successList)let errorList = value.filter(item => item.status === 'rejected');console.log(errorList)
}).catch(error => {console.log(error);
})
</script>

9.7 Promise.any()

只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfiilled状态;

如果所有参数实例都变成rejected,包装实例就会变成rejected状态。

Promise.any()跟Promise.race()方法很像,但是有一点不同,

就是Promise.any()不会因为某个Promise变成rejected状态而结束,

必须等到所有参数Promise变成rejected状态才会结束。

<script>let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('ok');}, 1000)})let p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('okk');}, 2000)})let p3 = new Promise((resolve, reject) => {setTimeout(() => {reject('error');}, 3000)})Promise.any([p1, p2, p3]).then(res => {console.log(res)}).catch(err => {console.log('error')})
</script>

9.8 Promise.finally()

finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象变成fufilled还是rejected状态,最终都会被执行。

finally方法中的回调函数是不接受参数的,因为无论前面是fulfilled状态还是rejected状态, 它都是执行。

const p = new Promise((resolve, reject) => {// resolve('ok');reject('error');
});
p.then(res => {console.log(res);
}).catch(err => {console.log(err);
}).finally(() => {console.log('finally')
})

十、终止Promise链条

new Promise((resolve, reject) => {resolve(111);
}).then(value=>{console.log(value);console.log(222);//// return false;// throw '出错啦';//有且只有一种方式 返回一个pending状态的promise对象return new Promise((resolve, reject) => {});
}).then(value => {console.log(333);
}).then(value => {console.log(444);
}).catch(reason => {console.log(reason);
});

十一、几个关键问题

11.1 如何修改 promise 对象状态

<script>//如何修改 promise 对象状态let p = new Promise((resolve, reject) => {//1. resolve// resolve('success');//2. reject// reject('error');//3. 抛出错误 异常// throw '出问题啦! 你说出这样的话  你没有良心!!';// 状态的改变只有一次 resolve('ok');reject('error');});console.log(p);
</script>

11.2 指定多个回调执行情况

问题:一个promise指定多个成功/失败回调函数,都会调用吗?

答:会,但是前提是当promise对象的状态改变(fulfilled/rejected)时才会调用

<script>let p = new Promise((resolve, reject) => {//promise对象是可以多次调用then方法完成多个成功/失败回调函数//但是使用的前提是这个promise对象的状态必须要么是fulfilled或者是rejected//不能是pendingresolve('OK');});	//第一次指定回调p.then(value => {console.log(value);}, reason => {console.error(reason);});p.then(value => {alert(value);}, reason => {alert(reason);})
</script>

11.3 指定回调与改变状态先后顺序问题

改变promise状态和指定回调函数执行谁先谁后?

  • 都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态在指定回调

    //若执行器函数中是异步任务, 则先指定回调, 然后再改变状态  更为常见
    //若执行器函数中是同步任务, 则先改变状态, 然后再指定回调
    let p = new Promise((resolve, reject) => {//同步任务//resolve('ok');//异步任务setTimeout(() => {resolve('ok');}, 1000);
    });
    
  • 如何先改状态再指定回调?

    • 在执行器中直接调用resolve()/reject()
    let p = new Promise((resolve, reject) => {//resolve('ok');reject('error');
    });
    
    • 延迟更长时间才调用then()
    const p = new Promise((resolve, reject) => {setTimeout(() => {resolve('ok');}, 1000)})
    //then方法使用定时器延迟更久的时间
    setTimeout(() => {p.then(value => {console.log(value);}, reason => {console.log(reason);})}, 3000)
    
  • 什么时候才能得到数据?

    • 如果是先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
    • 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据

11.4 promise.then()返回的新promise的结果状态由什么决定?

  • 简单表达:由then指定的回调函数执行的结果决定
  • 详细表达:
    • 如果抛出异常:新promise对象状态变成rejected,reason为抛出的异常
    • 如果返回的是是非promise的任意值,新promise对象状态变成fulfilled,value为返回的值
    • 如果返回的是另一个新的promise对象,此promise的结果就会称为新promise的结果
const p = new Promise((resolve, reject) => {resolve('ok');
})
let result = p.then(value => {//return value;return new Promise((resolve, reject) => {resolve('okk');})
}, reason => {console.log(reason);
})
console.log(result);

11.5 promise如何串联多个操作任务?

  • promise的then()返回一个新的promise对象,可以写成then()方法的链式调用
  • 通过then()的链式调用串联多个同步/异步任务
<script>new Promise((resolve, reject) => {console.log(111);reject();}).then(value => {console.log(222);}).then(value=> {console.log(value);}).then(value => {console.log(value)}, reason => {console.error(reason);});
</script>

11.6 promise的异常穿透

  • 当使用promise的then链式调用时, 可以在最后指定失败的回调,
  • 前面任何操作出了异常, 都会传到最后失败的回调中处理
new Promise((resolve, reject) => {console.log(111);reject('error');
}).then(value => {console.log(222);
}).then(value => {console.log(value);
}).then(value => {console.log(value)
}).catch(reason => {console.log(reason);
})

11.7 中断promise链

  • 当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
  • 办法: 在回调函数中返回一个pending状态的promise对象
new Promise((resolve, reject) => {console.log(111);resolve('ok');
}).then(value => {console.log(222);
}).then(value => {console.log(value);return new Promise(() => { })
}).then(value => {console.log(value)
}, reason => {console.error(reason);
});

十二、async和await

async/await 是ES7提出的基于Promise的解决异步的最终方案。

12.1 async函数

async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。

因此对async函数可以直接then,返回值就是then方法传入的函数。

// async基础语法
async function fun0(){console.log(1);return 1;
}
fun0().then(val=>{console.log(val) // 1,1
})async function fun1(){console.log('Promise');return new Promise(function(resolve,reject){resolve('Promise')})
}
fun1().then(val => {console.log(val); // Promise Promise
}
//声明一个async函数
async function main() {console.log('async function');//情况1:返回非promise对象数据return 'hahaha';//情况2:返回是promise对象数据/* return new Promise((resolve, reject) => {// resolve('ok');reject('error');}) *///情况3:抛出异常// throw new Error('出错啦!!!');
}
let result = main().then(value => {console.log(value);
});
console.log(result);

12.2 await表达式

await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待

await 修饰的如果是Promise对象,可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语

句才会往下执行;如果不是Promise对象:把这个非promise的东西当做await表达式的结果。

注意事项

  • await必须写在async函数中,但是async函数中可以没有await
  • 如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
async function fun(){let a = await 1;let b = await new Promise((resolve,reject)=>{setTimeout(function(){resolve('setTimeout')},3000)})let c = await function(){return 'function'}()console.log(a,b,c)
}
fun(); // 3秒后输出: 1 "setTimeout" "function"
function log(time){setTimeout(function(){console.log(time);return 1;},time)
}
async function fun(){let a = await log(1000);let b = await log(3000);let c = log(2000);console.log(a);console.log(1)
}
fun(); 
// 立即输出 undefined 1
// 1秒后输出 1000
// 2秒后输出 2000
// 3秒后输出 3000
async function main() {//1、如果await右侧为非promise类型数据var rs = await 10;var rs = await 1 + 1;var rs = await "非常6+7";//2、如果await右侧为promise成功类型数据var rs = await new Promise((resolve, reject) => {resolve('success');})//3、如果await右侧为promise失败类型数据,需要借助于try...catch捕获try {var rs = await new Promise((resolve, reject) => {reject('error');})} catch (e) {console.log(e);}
}
main();
// 使用async/await获取成功的结果// 定义一个异步函数,3秒后才能获取到值(类似操作数据库)
function getSomeThing(){return new Promise((resolve,reject)=>{setTimeout(()=>{resolve('获取成功')},3000)})
}async function test(){let a = await getSomeThing();console.log(a)
}
test(); // 3秒后输出:获取成功

案例:async结合await读取文件内容

//1、导包
const fs = require('fs');
const {promisify} = require('util');
//2、将fs.readFile转化成promise风格的函数
const myreadfile = promisify(fs.readFile);
//3、声明async函数
async function main(){try{//4、读取文件let one = await myreadfile('./resource/4.html');let two = await myreadfile('./resource/2.html');let three = await myreadfile('./resource/3.html');//5、拼接读取文件内容console.log(one + two + three);}catch(e){console.log(e);}
}
//6、调用main函数
main();

十三、JS中的宏队列与微队列

  • 说明
    • JS中用来存储待执行回调函数的队列包含2个不同特定的列队
    • 宏列队: 用来保存待执行的宏任务(回调), 比如: 定时器回调/DOM事件回调/ajax回调
    • 微列队: 用来保存待执行的微任务(回调), 比如: promise的回调/MutationObserver的回调
    • JS执行时会区别这2个队列
      • JS引擎首先必须先执行所有的初始化同步任务代码
      • 每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行
setTimeout(() => {console.log(111);
});new Promise((resolve, reject) => {resolve();//return ;throwreject();console.log(222);
}).then(v => {console.log(333);
})
console.log(444);

十四、Promise常见面试题

setTimeout(() => {console.log(1)
}, 0)
Promise.resolve().then(() => {console.log(2)
})
Promise.resolve().then(() => {console.log(4)
})
console.log(3)
setTimeout(() => {console.log(1)
}, 0)
new Promise((resolve) => {console.log(2)resolve()
}).then(() => {console.log(3)
}).then(() => {console.log(4)
})
console.log(5)
const first = () => (new Promise((resolve, reject) => {console.log(3)let p = new Promise((resolve, reject) => {console.log(7)setTimeout(() => {console.log(5)resolve(6)}, 0)resolve(1)})resolve(2)p.then((arg) => {console.log(arg)})}))
first().then((arg) => {console.log(arg)
})
console.log(4)
setTimeout(() => {console.log("0")
}, 0)
new Promise((resolve, reject) => {console.log("1")resolve()
}).then(() => {console.log("2")new Promise((resolve, reject) => {console.log("3")resolve()}).then(() => {console.log("4")}).then(() => {console.log("5")})
}).then(() => {console.log("6");
})new Promise((resolve, reject) => {console.log("7")resolve()
}).then(() => {console.log("8")
});

十五、手写promise自定义基础结构的搭建

15.1 Promise 的基本结构

/*** 1- Promise 是一个构造函数* 2- Promise 接收一个参数,该参数的类型是函数(执行器函数executor)* 3- executor接收两个参数(resolve,reject),参数的类型是函数* 4- 执行器函数会同步执行。* 5- then方法在其显式原型属性上*/// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){executor(function(){},function(){});}window.Promise = Promise;
})(window);
new Promise((resolve, reject)=>{console.log("这是我的执行器函数",resolve,reject)
})
console.log("over",Promise);

15.2 Promise实例拥有两个实例属性

/** 1- Promise实例拥有两个实例属性:* 状态([[PromiseState]]),初始状态为pending* 值([[PromiseResult]]),初始值为undefined
*/ 
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;executor(function(){},function(){});}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{console.log("这是我的执行器函数",resolve,reject)
})
console.log(p1);

15.3 更改状态三种方式-方法未抽离

/** 更改状态三种方式* 1- 通过调用resolve将状态更改为成功(fulfilled),接收的值为成功值* 2- 通过调用reject将状态更改为失败(rejected),接收的值为失败值* 3- 抛出异常将状态更改为失败(rejected),失败的值为异常信息。
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;try{executor(function(value){// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}.bind(this),function(value){// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}.bind(this));}catch (err){// 将状态更改为失败this.state = "rejected";// 将异常信息作为失败值this.result = err;}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);// reject(2);throw "异常"
})
console.log(p1);

15.4 更改状态三种方式-抽离为普通函数

// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = function(value){// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}.bind(this)// 定义reject函数const _reject = function(value){// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}.bind(this)try{executor(_resolve,_reject);}catch (err){// 将状态更改为失败this.state = "rejected";// 将异常信息作为失败值this.result = err;}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);reject(2);// throw "异常"
})
console.log(p1);

15.5 更改状态三种方式-抽离为箭头函数

// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){// 将状态更改为失败this.state = "rejected";// 将异常信息作为失败值this.result = err;}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);// reject(2);throw "异常"
})
console.log(p1);

15.6 状态只允许更改一次

/** pending-> fulfilled* pending-> rejected* 改变状态只有这两种,且一个promise对象只能改变一次,,无论变成成功还是失败,都会有一个结果值* 成功的结果数据一般称为value,失败的结果值一般称为reason
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{resolve(1);reject(2);throw "异常"
})
console.log(p1);

15.7 then函数调用成功或失败回调函数

/** 1- then是Promise中的原型方法* 2- then函数接收两个参数(成功回调,失败回调)* 3- 如果p1状态为成功执行成功回调,失败执行失败回调。
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 状态成功调用onResolvedif(this.state === "fulfilled"){onResolved(this.result);}else if(this.state === "rejected"){onRejected(this.result);}},catch(){}})window.Promise = Promise;
})(window);

15.8 then函数中的回调函数是异步调用的

// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 状态成功调用onResolvedif(this.state === "fulfilled"){// 异步调用setTimeout(()=>{onResolved(this.result);})}else if(this.state === "rejected"){// 异步调用setTimeout(()=>{onRejected(this.result);})}},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);// reject(2);throw "异常"
})
p1.then(value=>{console.log("成功回调",value);
},reason=>{console.log("失败回调",reason);
})
console.log("over");

15.9 then函数返回的是一个Promise实例

// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){return new Promise((resolve,reject)=>{// 状态成功调用onResolvedif(this.state === "fulfilled"){// 异步调用setTimeout(()=>{onResolved(this.result);})}else if(this.state === "rejected"){// 异步调用setTimeout(()=>{onRejected(this.result);})}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);// reject(2);throw "异常"
})
const p2 = p1.then(value=>{console.log("成功回调",value);
},reason=>{console.log("失败回调",reason);
})
console.log(p2);

15.10 then函数返回的Promise实例状态以及值-未优化

/** then返回的Promise实例受成功或失败回调函数返回值的影响* 1- 如果返回的是非Promise,那么p2状态为成功,值为返回值* 2- 如果返回的是Promise,那么p2状态以及值与返回的状态,值相同。* 3- 如果出现异常,那么p2状态为失败,值为异常信息。
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){return new Promise((resolve,reject)=>{// 状态成功调用onResolvedif(this.state === "fulfilled"){// 异步调用setTimeout(()=>{try{// value是成功回调的返回值const value = onResolved(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise){// value.then(v=>{// 	// 将返回的Promise实例设置为成功,值为v// 	resolve(v);// },s=>{// 	// 将返回的Promise实例设置为失败,值为s// 	reject(s);// })// 简化:value.then(resolve,reject)}else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}else if(this.state === "rejected"){// 异步调用setTimeout(()=>{try{// value是失败回调的返回值const value = onRejected(this.result);// value是否为Promise实例if(value instanceof Promise){// 将返回Promise设置为与value相同的结果value.then(resolve,reject);}else{// 返回成功promise,值为valueresolve(value);}}catch (err){// 返回失败promise,值为errreject(err);}})}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);reject(2);// throw "异常"
})
const p2 = p1.then(value=>{return new Promise((resolve,reject)=>{// resolve(100)// reject(200)throw "异常2"})// return 1;// console.log("成功回调",value);
},reason=>{return new Promise((resolve,reject)=>{// resolve(100);// reject(2)throw "异常3"})// return 1;// console.log("失败回调",reason);
})
console.log(p2);

15.11 then函数返回的Promise实例状态以及值-优化封装函数_common

// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise){value.then(resolve,reject);}else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);reject(2);// throw "异常"
})
const p2 = p1.then(value=>{// return new Promise((resolve,reject)=>{// 	// resolve(100)// 	// reject(200)throw "异常2"// })// return 1;// console.log("成功回调",value);
},reason=>{// return new Promise((resolve,reject)=>{// 	// resolve(100);// 	// reject(2)// 	throw "异常3"// })// return 1;// console.log("失败回调",reason);
})
console.log(p2);

15.12 增加成功与失败回调函数的默认值

/** 1- then如果省略成功回调,默认成功回调为 value=>value;* 2- then如果省略失败回调,默认失败回调为 reason=>{throw reason};
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise){value.then(resolve,reject);}else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{resolve(1);// reject(2);
})
const p2 = p1.then();
console.log(p2);

15.14 执行器函数常用于处理异步行为

(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = {};// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;if(this.callbackFn.onResolved){this.callbackFn.onResolved();}}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "fulfilled";// 将result设置为valuethis.result = value;if(this.callbackFn.onRejected){this.callbackFn.onRejected();}}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn = {onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)}}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(100);})
})
p1.then(value=>{console.log(value);
},reason=>{console.log("失败",reason);
})

15.15 可以指定多个成功或失败的回调

(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "fulfilled";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(){}})window.Promise = Promise;
})(window);
// 可以指定多个成功或失败的回调
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(100);})
})
p1.then(value=>{console.log("成功1",value);
},reason=>{console.log("失败1",reason);
})
p1.then(value=>{console.log("成功2",value);
},reason=>{console.log("失败2",reason);
})
p1.then(value=>{console.log("成功3",value);
},reason=>{console.log("失败3",reason);
})
p1.then(value=>{console.log("成功4",value);
},reason=>{console.log("失败4",reason);
})

15.16 catch

(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "fulfilled";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})window.Promise = Promise;
})(window);
// 可以指定多个成功或失败的回调
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(100);})
})
// p1.then(undefined,reason=>{
// 	console.log(reason);
// })
// catch的返回值是Promise实例,实例的属性与值取决于回调函数的返回值
// 返回值为非Promise实例,那么得到的状态为成功,值为返回值
// 返回值为Promise实例,那么得到的结果与返回的结果相同。
// 有异常,那么得到的状态为失败,值为异常信息。
const p2 = p1.catch(reason=>{// console.log(reason);return new Promise((resolve,reject)=>{resolve(2);})// throw "异常"
})
console.log(p2);

15.17 链式调用支持

(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})window.Promise = Promise;
})(window);
new Promise((resolve,reject)=>{resolve(1);
}).then(value=>{console.log(value);// 1return 2;
}).then(value=>{console.log(value);// 2return 3;
}).then(value=>{console.log(value);// 3return 4;
}).then(value=>{console.log(value);// 4return 5;
})

15.18 异常穿透支持

(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})window.Promise = Promise;
})(window);
new Promise((resolve, reject) => {resolve(1);
}).then(value => {throw "异常"
}).then(value => {console.log(value);return 3;
}).then(value => {console.log(value);// 3return 4;
}).then(value => {console.log(value);// 4return 5;
}).catch(reason => {console.log(4,reason);
})

15.19 中断Promise链

(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})window.Promise = Promise;
})(window);
new Promise((resolve,reject)=>{resolve(1);
}).then(value=>{console.log(value);// 1return 2;
}).then(value=>{console.log(value);// 2// 在回调函数中返回一个`pendding`状态的promise对象return new Promise(()=>{})
}).then(value=>{console.log(value);// undefinedreturn 4;
}).then(value=>{console.log(value);// 4return 5;
})

15.20 resolve

(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})Promise.resolve = function(value){if(value instanceof Promise){return value;// 如果是Promise实例直接返回}else{// 如果不是Promise实例,那么返回的状态为成功,值为valuereturn new Promise(resolve=>{resolve(value);})}}window.Promise = Promise;
})(window);
// const p1 = Promise.resolve(1);
// console.log(p1);// const p1 = Promise.resolve(new Promise((resolve,reject)=>{
// 	resolve(2);
// }));
// console.log(p1);
//
// const p1 = Promise.resolve(new Promise((resolve,reject)=>{
// 	reject(2);
// }));
// console.log(p1);const p =new Promise((resolve,reject)=>{reject(2);
})
const p1 = Promise.resolve(p);
console.log(p1===p);

15.21 reject

(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>value;}// 如果失败回调不是函数,那么增加失败回调默认值if(!(onRejected instanceof Function)){onRejected = reason=>{throw reason;};}return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})Promise.resolve = function(value){if(value instanceof Promise){return value;// 如果是Promise实例直接返回}else{// 如果不是Promise实例,那么返回的状态为成功,值为valuereturn new Promise(resolve=>{resolve(value);})}}Promise.reject = function(value){return new Promise((resolve,reject)=>{reject(value);})}window.Promise = Promise;
})(window);
const p1 = Promise.reject(1);
console.log(p1);const p2 = Promise.reject(new Promise((resolve,reject)=>{resolve(2);
}));
console.log(p2);const p3 = Promise.reject(new Promise((resolve,reject)=>{reject(2);
}));
console.log(p3);

15.22 完成all

(function (window) {// 接收执行器函数(executor),执行器函数会同步执行(立即执行)。function Promise(executor) {this.state = "pending";// 初始状态this.result = undefined;// 初始值this.callbackFn = [];// _resolve函数将状态更新为成功,成功值为接收的valueconst _resolve = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "fulfilled";// 状态更新为成功this.result = value;// 更新成功值this.callbackFn.forEach(item=>{item.onResolved();})}// _reject函数将状态更新为失败,失败值为接收的valueconst _reject = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "rejected";// 状态更新为失败this.result = value;// 更新失败值this.callbackFn.forEach(item=>{item.onRejected();})}try {executor(_resolve, _reject);} catch (err) {// 如果有异常,将状态更新为失败,失败的值为异常信息_reject(err);}}// 将第二个参数(对象)合并至Promise.prototype对象中。Object.assign(Promise.prototype, {// 1- 接收成功与失败回调函数// 2- 返回的是一个Promise实例// 3- onResolved成功回调,默认值为value=>value;// 4- onRejected失败回调,默认值为reason=>{throw reason};then(onResolved, onRejected) {// onResolved成功回调,默认值为value=>value;if (!(onResolved instanceof Function)) onResolved = value => value;//onRejected失败回调,默认值为reason=>{throw reason};if (!(onRejected instanceof Function)) onRejected = reason => {throw reason};return new Promise((resolve, reject) => {// callback是成功或失败回调const _common = function (callback) {setTimeout(()=>{try {// value是成功回调返回结果const value = callback(this.result);// 判断是否为Promise实例if (value instanceof Promise) {value.then(resolve, reject);} else {// 非Promise实例resolve(value);}} catch (err) {reject(err);}})}// 判断状态为成功,调用成功回调if (this.state === "fulfilled") _common.call(this, onResolved);else if (this.state === "rejected") _common.call(this, onRejected);else {this.callbackFn.push({onResolved: _common.bind(this, onResolved),onRejected: _common.bind(this, onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected);}})Promise.resolve = function(value){// 判断接收的参数是否为Promise实例,如果是直接返回if(value instanceof Promise){return value;}else{// 如果不是,创建一个新的Promise,状态为成功,值为value;return new Promise(resolve=>{resolve(value);})}}Promise.reject = function(value){// 返回失败的Promise,失败值为接收的valuereturn new Promise((resolve,reject)=>{reject(value);})}// 1- 接收的是数组,返回的是PromisePromise.all = function(promiseArr){let index = 0;let successArr = new Array(promiseArr.length);return new Promise((resolve,reject)=>{promiseArr.forEach((value,i)=>{value.then(v=>{index++;successArr[i] = v;if(index === promiseArr.length){resolve(successArr);}},s=>{// 返回Promise的状态设置失败reject(s);})})})}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(100)},100)
})
const p2 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(200)},50)
})
const p3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(300)},200)
})
const p4 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(400)},100)
})
// all接收的数组中的元素是Promise实例。
// 元素中的Promise实例都成功,p的状态为成功,值为数组,数组的元素为成功值
// 元素中有一个失败,那么p的状态为失败,值为失败值
const p = Promise.all([p1,p2,p3,p4]);
console.log(p);

15.23 完成race

(function (window) {// 接收执行器函数(executor),执行器函数会同步执行(立即执行)。function Promise(executor) {this.state = "pending";// 初始状态this.result = undefined;// 初始值this.callbackFn = [];// _resolve函数将状态更新为成功,成功值为接收的valueconst _resolve = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "fulfilled";// 状态更新为成功this.result = value;// 更新成功值this.callbackFn.forEach(item=>{item.onResolved();})}// _reject函数将状态更新为失败,失败值为接收的valueconst _reject = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "rejected";// 状态更新为失败this.result = value;// 更新失败值this.callbackFn.forEach(item=>{item.onRejected();})}try {executor(_resolve, _reject);} catch (err) {// 如果有异常,将状态更新为失败,失败的值为异常信息_reject(err);}}// 将第二个参数(对象)合并至Promise.prototype对象中。Object.assign(Promise.prototype, {// 1- 接收成功与失败回调函数// 2- 返回的是一个Promise实例// 3- onResolved成功回调,默认值为value=>value;// 4- onRejected失败回调,默认值为reason=>{throw reason};then(onResolved, onRejected) {// onResolved成功回调,默认值为value=>value;if (!(onResolved instanceof Function)) onResolved = value => value;//onRejected失败回调,默认值为reason=>{throw reason};if (!(onRejected instanceof Function)) onRejected = reason => {throw reason};return new Promise((resolve, reject) => {// callback是成功或失败回调const _common = function (callback) {setTimeout(()=>{try {// value是成功回调返回结果const value = callback(this.result);// 判断是否为Promise实例if (value instanceof Promise) {value.then(resolve, reject);} else {// 非Promise实例resolve(value);}} catch (err) {reject(err);}})}// 判断状态为成功,调用成功回调if (this.state === "fulfilled") _common.call(this, onResolved);else if (this.state === "rejected") _common.call(this, onRejected);else {this.callbackFn.push({onResolved: _common.bind(this, onResolved),onRejected: _common.bind(this, onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected);}})Promise.resolve = function(value){// 判断接收的参数是否为Promise实例,如果是直接返回if(value instanceof Promise){return value;}else{// 如果不是,创建一个新的Promise,状态为成功,值为value;return new Promise(resolve=>{resolve(value);})}}Promise.reject = function(value){// 返回失败的Promise,失败值为接收的valuereturn new Promise((resolve,reject)=>{reject(value);})}// 1- 接收的是数组,返回的是PromisePromise.all = function(promiseArr){let index = 0;let successArr = new Array(promiseArr.length);return new Promise((resolve,reject)=>{promiseArr.forEach((value,i)=>{value.then(v=>{index++;successArr[i] = v;if(index === promiseArr.length){resolve(successArr);}},s=>{// 返回Promise的状态设置失败reject(s);})})})}Promise.race = function(promiseArr){return new Promise((resolve,reject)=>{promiseArr.forEach(value=>{// value.then(v=>{// 	resolve(v);// },s=>{// 	reject(s);// })value.then(resolve,reject);})})}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(100)},100)
})
const p2 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(200)},50)
})
const p3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(300)},200)
})
const p4 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(400)},100)
})
// race:返回的是Promise实例,谁先执行完就与谁的状态以及值相同。
const p = Promise.race([p1,p2,p3,p4]);
console.log(p);

15.24 class版本实现Promise

(function (window) {// 1-将之前构造函数体内的语句放置到constructor函数中// 2-将之前prototype的属性直接放置到Promise中class Promise{static resolve(value){// 判断接收的参数是否为Promise实例,如果是直接返回if(value instanceof Promise){return value;}else{// 如果不是,创建一个新的Promise,状态为成功,值为value;return new Promise(resolve=>{resolve(value);})}}static reject(value){// 返回失败的Promise,失败值为接收的valuereturn new Promise((resolve,reject)=>{reject(value);})}static all(promiseArr){let index = 0;let successArr = new Array(promiseArr.length);return new Promise((resolve,reject)=>{promiseArr.forEach((value,i)=>{value.then(v=>{index++;successArr[i] = v;if(index === promiseArr.length){resolve(successArr);}},s=>{// 返回Promise的状态设置失败reject(s);})})})}static race(promiseArr){return new Promise((resolve,reject)=>{promiseArr.forEach(value=>{// value.then(v=>{// 	resolve(v);// },s=>{// 	reject(s);// })value.then(resolve,reject);})})}constructor(executor) {this.state = "pending";// 初始状态this.result = undefined;// 初始值this.callbackFn = [];// _resolve函数将状态更新为成功,成功值为接收的valueconst _resolve = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "fulfilled";// 状态更新为成功this.result = value;// 更新成功值this.callbackFn.forEach(item=>{item.onResolved();})}// _reject函数将状态更新为失败,失败值为接收的valueconst _reject = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "rejected";// 状态更新为失败this.result = value;// 更新失败值this.callbackFn.forEach(item=>{item.onRejected();})}try {executor(_resolve, _reject);} catch (err) {// 如果有异常,将状态更新为失败,失败的值为异常信息_reject(err);}}then(onResolved, onRejected) {// onResolved成功回调,默认值为value=>value;if (!(onResolved instanceof Function)) onResolved = value => value;//onRejected失败回调,默认值为reason=>{throw reason};if (!(onRejected instanceof Function)) onRejected = reason => {throw reason};return new Promise((resolve, reject) => {// callback是成功或失败回调const _common = function (callback) {setTimeout(()=>{try {// value是成功回调返回结果const value = callback(this.result);// 判断是否为Promise实例if (value instanceof Promise) {value.then(resolve, reject);} else {// 非Promise实例resolve(value);}} catch (err) {reject(err);}})}// 判断状态为成功,调用成功回调if (this.state === "fulfilled") _common.call(this, onResolved);else if (this.state === "rejected") _common.call(this, onRejected);else {this.callbackFn.push({onResolved: _common.bind(this, onResolved),onRejected: _common.bind(this, onRejected)})}})}catch(onRejected){return this.then(undefined,onRejected);}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(100)},100)
})
const p2 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(200)},50)
})
const p3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(300)},200)
})
const p4 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(400)},100)
})
// race:返回的是Promise实例,谁先执行完就与谁的状态以及值相同。
const p = Promise.race([p1,p2,p3,p4]);
console.log(p);

来源:尚硅谷

相关文章:

Promise详解

目录 一、前言&#xff1a;为什么会出现Promise?二、Promise是什么?2.1 Promise的初体验 三、使用Promise的好处?3.1 指定回调函数的方式更加灵活3.2 可以解决回调地狱问题&#xff0c;支持链式调用 四、Promise实例对象的两个属性五、resolve函数以及reject函数六、Promise…...

Oracle 查询(当天,月,年)的数据

Trunc 在oracle中&#xff0c;可利用 trunc函数 查询当天数据&#xff0c;该函数可用于截取时间或者数值&#xff0c;将该函数与 select 语句配合使用可查询时间段数据 查询当天数据 --sysdate是获取系统当前时间函数 --TRUNC函数用于截取时间或者数值&#xff0c;返回指定的…...

什么是梯度下降

什么是梯度下降 根据已有数据的分布来预测可能的新数据&#xff0c;这是回归 希望有一条线将数据分割成不同类别&#xff0c;这是分类 无论回归还是分类&#xff0c;我们的目的都是让搭建好的模型尽可能的模拟已有的数据 除了模型的结构&#xff0c;决定模型能否模拟成功的关键…...

开黑啦kook 机器人开发 PHP swoole Liunx 服务器(宝塔)

安装环境 PHP 拓展 直接使用 宝塔一键安装 &#xff08;Windows系统不支持&#xff09; 设置命令行的PHP版本避免执行脚本时 获取不到 swoole 检查swoole是否安装成功 获取官方SDK GitHub - kaiheila/php-bot: 开黑啦机器人的php版本https://github.com/kaiheila/php-bot 配…...

Vue 中hash 模式与 history 模式的区别

hash 模式&#xff1a; - 地址中永远带着 # 号&#xff0c;不美观。 - 兼容性比较好。 - 通过手机 app 分享地址时&#xff0c;如果 app 效验严格&#xff0c;该地址会被标记为不合法。 history 模式&#xff1a; - 地址干净&#xff0c;美观。 - 兼容性和 hash 模式相比…...

Dockerfile推送私有仓库的两个案例

一&#xff0c;编写Dockerfile制作Web应用系统nginx镜像&#xff0c;生成镜像nginx:v1.1&#xff0c;并推送其到私有仓库。 具体要求如下&#xff1a; &#xff08;1&#xff09;基于centos基础镜像&#xff1b; &#xff08;2&#xff09;指定作者信息&#xff1b; &#xff…...

【指标】指标公式大全,款款经典(建议珍藏)!-神奇指标网

三、指标源码&#xff1a; 1、连续三天高开高走的选股公式 count(o〉ref(c,1&#xff09;andc>o&#xff0c;3)3&#xff1b; 2、连续3天每天的最低价都比前一天高 count&#xff08;l〉ref(c,1&#xff09;,3)3&#xff1b; 3、周量缩小50%或40&#xff05;或n&#x…...

面试题目收集

Zset排行榜功能如何设计key&#xff1f; key就设计成排行榜的名字&#xff0c;比如下面插入或者更新数据 Long zadd(final String key, final double score, final String member) key : 排行榜的名字 memeber : 用户 score : 用户的分数 项目…...

创建R包-2.1:在RStudio中使用Rcpp制作R-Package(更新于2023.8.23)

目录 0-前言 1-在RStudio中创建R包项目 2-创建R包 2.1通过R函数创建新包 2.2在RStudio通过菜单来创建一个新包 2.3关于R包创建的说明 3-添加R自定义函数 4-添加C函数 0-前言 目标&#xff1a;在RStudio中创建一个R包&#xff0c;这个R包中包含C函数&#xff0c;接口是Rc…...

chatGPT如何解释泽众PerformanceRunner性能测试工具?

PerformanceRunner 是一个性能测试工具&#xff0c;可以帮助测试人员进行性能测试。它的主要功能包括&#xff1a; 1. 脚本录制和回放&#xff1a; PerformanceRunner可以录制 HTTP/HTTPS 通信协议的脚本&#xff0c;并能够回放模拟真实用户的行为。通过录制和回放&#xff0c…...

LA@向量组线性相关性

文章目录 向量组线性相关性线性相关线性无关多向量向量组线性相关单向量向量组的线性相关性单位向量向量组线性相关性双向量向量组的线性相关性双向量线性相关的几何意义三向量线性相关的几何意义包含零向量的向量组线性相关概念迁移:线性方程组和线性相关齐次线性方程组和向量…...

[k8s] 基于ubuntu22部署k8s1.28记录

k8s1.28部署已经不依赖docker了&#xff0c;所以不需要安装docker。同理&#xff1a;如果想查看镜像和运行容器&#xff0c;也不能用docker命令去查询了&#xff1a;需要使用crictl。不过crictl命令参数兼容docker&#xff0c;所以使用上手没有啥难度。 1. 配置安装源 根据k8…...

React 事件代理 和原生事件绑定混用:你的选择会导致什么问题?

在React开发中&#xff0c;事件处理是一个常见的任务。React提供了一个方便的事件系统&#xff0c;但有时我们可能会在React组件中与原生DOM事件一起使用。本文将讨论React的事件代理机制与原生事件绑定混用可能导致的一些问题。 React的事件代理 React采用了一种称为"事…...

使用阿里云国外和国内云服务器有什么注意事项?

使用阿里云的国外和国内云服务器时&#xff0c;有一些注意事项需要考虑&#xff1a; 地理位置&#xff1a;选择离你的用户或数据中心最近的地理位置&#xff0c;可以减少延迟和提高访问速度。对于国内用户&#xff0c;使用国内云服务器可能更好&#xff1b;对于国外用户&#…...

【计算机网络】【常考问题总结】

1. ping 127.0.0.1 后会发生什么&#xff1f; ping 127.0.0.1 &#xff1b;ping 0.0.0.0 &#xff1b; ping localhost 面试官问&#xff1a;断网了&#xff0c;还能ping通 127.0.0.1 吗&#xff1f;为什么&#xff1f;_kevin_tech的博客-CSDN博客 2. MTU&#xff0c;MMU是…...

前端基础(props emit slot 父子组件间通信)

前言&#xff1a;如何实现组件的灵活使用&#xff0c;今天学习组件封装用到的props、slot和emit。 目录 props 子组件 父组件 示例代码 slot 示例代码 作用域插槽 emit 示例代码 props 需要实现在其他组件中使用同一个子组件。 子组件 子组件&#xff08;所谓子组件…...

即时通讯:短轮询、长轮询、SSE 和 WebSocket 间的区别

在现代 Web 开发中&#xff0c;即时通讯已经成为许多应用程序的重要组成部分。为了实现即时通讯&#xff0c;开发人员通常使用不同的技术和协议。本文将介绍四种常见的即时通讯实现方法&#xff1a;短轮询、长轮询、SSE&#xff08;服务器发送事件&#xff09;和 WebSocket&…...

高忆管理:药店零售概念回落,开开实业走低,此前7日大涨超80%

药店零售概念18日盘中大幅下挫&#xff0c;到发稿&#xff0c;华人健康跌逾11%&#xff0c;漱玉布衣、塞力医疗跌超9%&#xff0c;重药控股、浙江震元、榜首医药等跌超7%&#xff0c;药易购跌超6%&#xff0c;开开实业跌超3%。 值得注意的是&#xff0c;开开实业此前7个交易日斩…...

Go1.19 排序算法设计实践 经典排序算法对比

详解经典排序算法 01 为什么要学习数据结构与算法 抖音直播排行榜功能 案例 规则&#xff1a;某个时间段内&#xff0c;直播间礼物数TOP10房间获得奖励&#xff0c;需要在每个房间展示排行榜解决方案 •礼物数量存储在Redis-zset中&#xff0c;使用skiplist使得元素整体有序 •…...

3:Ubuntu上配置QT交叉编译环境并编译QT程序到Jetson Orin Nano(ARM)

1.Ubuntu Qt 配置交叉编译环境 1.1 ubuntu 20.04安装Qt sudo apt-get install qtcreator 1.2 配置QT GCC配置同上 最后配置Kits 上面设置完成之后 &#xff0c;设置Kits 中的Device(这是为了能够直接把项目部署到arm设备上) 点击NEXT之后会出现连接被拒绝&#xff0c;不用担…...

CentOS下MySQL的彻底卸载的几种方法

这里我为大家详细讲解下“CentOS下MySQL的彻底卸载的几种方法”的完整攻略。 前言 先通过下列命令找到需要删除的相关文件 rpm -qa mysql* whereis mysql find / -name mysql 需要上传的命令介绍 删除 MySQL 数据目录 rm -rf /var/lib/mysql 删除配置文件 rm -rf /etc/my.cnf…...

Spring 的异常处理机制

Spring 的异常处理机制 ​ 在Spring中&#xff0c;异常处理是一个非常重要的方面&#xff0c;用于捕获和处理应用程序中可能出现的异常情况。Spring提供了多种方式来处理异常。 ​ 使用Spring的异常处理机制主要有以下优点&#xff1a; ​ **统一的异常处理&#xff1a;**通…...

java八股文面试[JVM]——JVM参数

参考&#xff1a;JVM学习笔记&#xff08;一&#xff09;_卷心菜不卷Iris的博客-CSDN博客 堆参数调优入门 jdk1.7&#xff1a; jdk1.8&#xff1a; 面试题&#xff1a;给定-Xms Xmx -Xmn 问 最大的eden区域是多少M。 常用JVM参数 怎么对jvm进行调优&#xff1f;通过参数配…...

面试热题(复原ip地址)

有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址&#xff0c;但是 "0.011.255.24…...

【JavaSE】Java方法的使用

【本节目标】 1. 掌握方法的定义以及使用 2. 掌握方法传参 3. 掌握方法重载 4. 掌握递归 目录 1.方法概念及使用 1.1什么是方法(method) 1.2 方法定义 1.3 方法调用的执行过程 1.4 实参和形参的关系 2. 方法重载 2.1 为什么需要方法重载 2.2 方法重载概念 3. 递归 3.…...

Node.js 安装和配置(完整详细版)

在Windows上安装和配置Node.js&#xff1a; 下载Node.js安装程序&#xff1a; 前往Node.js官方网站&#xff08;https://nodejs.org/&#xff09;&#xff0c;在主页上找到"Downloads"&#xff08;下载&#xff09;选项。然后选择适用于Windows的"Windows Insta…...

剪枝基础与实战(4):稀疏训练及剪枝效果展示

稀疏训练是通过在损失loss中增加BN的 γ \gamma γ 参数的L1正则,从而让绝大多数通道对应的 γ \gamma γ值趋近与0, 从而使得模型达到稀疏化的效果:...

CentOS 7.6使用yum安装stress,源码安装stree-ng 0.15.06,源码安装sysstat 12.7.2

cat /etc/redhat-release看到操作系统的版本是CentOS Linux release 7.6.1810 (Core)&#xff0c;uname -r可以看到内核版本是3.10.0-957.21.3.el7.x86_64 yum install stress sysstat -y安装stress和sysstat。 使用pidstat -u 5 1没有%wait项&#xff1a; 原因是CentOS 7仓…...

POI groupRow 折叠分组,折叠部分不显示问题

折叠组是什么&#xff1f;如图就是用POI 实现的&#xff0c;代码很简单&#xff1a;sheet.groupRow(开始行&#xff0c;结束行)即可 但是万万没想到&#xff0c;最终实现出的结果&#xff0c;合并的组&#xff0c;有一部分并没有渲染出来&#xff0c;如下图&#xff1a; 因为我…...

一、数据库基础

数据库 一、数据库基础 1、一些概念 数据库&#xff1a;数据库&#xff08;DataBase &#xff0c;简称DB&#xff09;&#xff0c;就是信息的集合。数据库是由数据库管理系统管理的数据的集合&#xff1b;数据库管理系统&#xff1a;简称DBMS 。是一种操纵和管理数据库的大型…...

Harmony OS教程学习笔记

基础知识 1.如何修改程序启动的第一个页面&#xff1f; 不想使用创建的默认的页面&#xff0c;这时需要修改启动页面&#xff0c;修改的地方在EntryAbility文件中的onWindowStageCreate方法中。 onWindowStageCreate(windowStage: window.WindowStage) {// Main window is cr…...

605. 种花问题

链接 假设有一个很长的花坛&#xff0c;一部分地块种植了花&#xff0c;另一部分却没有。可是&#xff0c;花不能种植在相邻的地块上&#xff0c;它们会争夺水源&#xff0c;两者都会死去。给你一个整数数组 flowerbed 表示花坛&#xff0c;由若干 0 和 1 组成&#xff0c;其中…...

Elasticsearch 常见的简单查询

查看es中有哪些索引 请求方式&#xff1a;GET 请求地址&#xff1a;http://localhost:9200 /_cat/indices?v 参数&#xff1a;无 结果&#xff1a; 查看索引全部数据 请求方式&#xff1a;GET 请求地址&#xff1a;http://localhost:9200/index-2023-08/_search 参数&a…...

C#使用xamarin进行跨平台开发

使用 Xamarin 进行跨平台开发可以使用 C# 和 .NET 平台来开发移动应用程序&#xff0c;同时将代码在多个主要移动操作系统上运行&#xff0c;包括 Android 和 iOS。以下是在 C# 中使用 Xamarin 进行跨平台开发的一般步骤&#xff1a; 安装 Xamarin&#xff1a; 在开始之前&…...

xargs 的用法 在1个文件夹中批量删除文件,这些删除的文件名是另一个文件夹中的文件名。

xargs 的用法 在1个文件夹中批量删除文件&#xff0c;这些删除的文件名是另一个文件夹中的文件名。 1、问题背景 应用场景 1、问题背景 应用场景 在二进制部署docker时&#xff0c;会把docker的所有可执行文件复制到/usr/bin下。 如果说复制过去后&#xff0c;想要反悔&#x…...

集简云本周新增/更新:新增2大功能,集成2款应用,更新4款应用,新增近20个动作

本周更新概要 新增功能 新增功能&#xff1a;Claude2 新增功能&#xff1a;语聚AI对话助手对话背景设定 应用新增 新增应用&#xff1a;领星ERP 新增应用&#xff1a;slack(自建) 应用更新 更新应用&#xff1a;企业微信(代开发) 更新应用&#xff1a;阿里云效2020(新版…...

MySQL存储过程怎么写?看完这篇秒懂

今天测试一个数据展示模块&#xff0c;依赖于数据部推送数据&#xff0c;但是他们没有人员配合&#xff0c;为了赶工&#xff0c;于是自己徒手造数据&#xff0c;有些页面&#xff0c;要查看翻页和权限等相关的功能&#xff0c;手动造是不可能的&#xff0c;因为我懒....哈哈哈…...

STM32电源名词解释

STM32电源架构 常用名词 VCC Ccircuit 表示电路&#xff0c;即接入电路的电压。 VDD Ddevice 表示器件&#xff0c; 即器件内部的工作电压。 VSS Sseries 表示公共连接&#xff0c;通常指电路公共接地端电压。 VDDA Aanalog 表示模拟&#xff0c;是模拟电路部分的电源。主要为…...

《操作系统真象还原》学习笔记:第七章 中断

由于 CPU 获知了计算机中发生的某些事&#xff0c;CPU 暂停正在执行的程序&#xff0c;转而去执行处理该事件的程序&#xff0c;当这段程序执行完毕后&#xff0c;CPU 继续执行刚才的程序。整个过程称为中断处理&#xff0c;也称为中断。 把中断按事件来源分类&#xff0c;来自…...

【学习笔记之vue】These dependencies were not found:

These dependencies were not found:方案一 全部安装一遍 我们先浅试一个axios >> npm install axios 安装完报错就没有axios了&#xff0c;验证咱们的想法没有问题&#xff0c;实行&#xff01; ok...

【数据结构】实现栈和队列

目录 一、栈1.栈的概念及结构&#xff08;1&#xff09;栈的概念&#xff08;2&#xff09;栈的结构 2.栈的实现&#xff08;1&#xff09;类型和函数的声明&#xff08;2&#xff09;初始化栈&#xff08;3&#xff09;销毁&#xff08;4&#xff09;入栈&#xff08;5&#x…...

APT60DQ20BG-ASEMI新能源功率器件APT60DQ20BG

编辑&#xff1a;ll APT60DQ20BG-ASEMI新能源功率器件APT60DQ20BG 型号&#xff1a;APT60DQ20BG 品牌&#xff1a;ASEMI 封装&#xff1a;TO-3P 恢复时间&#xff1a;&#xff1e;50ns 正向电流&#xff1a;60A 反向耐压&#xff1a;200V 芯片个数&#xff1a;2 引脚数…...

[Android Framework] 系统 ANR 问题排查实践小结

文章目录 背景卡顿的定义:卡顿分类:卡顿原因汇总ANR 出现的原理应用层导致ANR系统导致ANR日志抓取traces.txt 是如何生成的分析思路与验证相关日志分析data/anr/traces.txt其他分析思路如何分析生成的 trace.html 文件呢?最后解决参考:背景 本文记录了工作中遇到的Andorid …...

【Unity】Text文本组件的一些操作

Unity的Text组件的几种常见的操作方法 Text组件是Unity中用于在UI界面上显示文本的组件。它包含了一些常见的属性和方法&#xff0c;可以用来控制文本的内容、外观和交互。以下是一些常见的Text组件的操作&#xff1a; 设置文本内容&#xff1a;通过直接在Unity编辑器中的Text…...

如何通过tomcat下载映射下载文件

1.1找到tomcat服务器中server.xml文件 !--doBase是静态资源路径位置&#xff0c; path作用相当于设置的key, doBase作用相当于value --> <Context path"/download" docBase"E:\testBackData"></Context>1.2 找到tomcat服务器中web.xml文…...

Redis的8种数据结构和应用场景介绍,面试题答案

面试原题&#xff1a;你用过Redis哪些数据结构&#xff1f;&#xff08;网易一面 2023&#xff09;(面试题来自牛客网) 参考答案 后面有 详细答案解析&#xff0c;帮助更快记忆~ 参考答案共652字符&#xff0c;阅读约需1分8秒&#xff1b;全文共8694字符&#xff0c;阅读约需…...

Log4Qt日志框架(1)- 引入到QT中

Log4Qt日志框架&#xff08;1&#xff09;- 引入到QT中 1 下载源码2 简介3 加入到自己的项目中3.1 使用库文件3.2 引入源文件 4 说明 1 下载源码 github&#xff1a;https://github.com/MEONMedical/Log4Qt 官方(版本较老)&#xff1a;https://sourceforge.net/projects/log4q…...

【算法刷题之哈希表篇(1)】

目录 1.哈希表基础理论2.leetcode-242. 有效的字母异位词&#xff08;1&#xff09;方法一&#xff1a;排序&#xff08;2&#xff09;方法二&#xff1a;哈希表 3.leetcode-349. 两个数组的交集&#xff08;1&#xff09;方法一&#xff1a;哈希表&#xff08;2&#xff09;方…...

uni-app 打包生成签名Sha1

Android平台打包发布apk应用&#xff0c;需要使用数字证书&#xff08;.keystore文件&#xff09;进行签名&#xff0c;用于表明开发者身份。 可以使用JRE环境中的keytool命令生成。以下是windows平台生成证书的方法&#xff1a; 安装JRE环境&#xff08;推荐使用JRE8环境&am…...

【Django】Django创建一个文件下载服务

当使用Django创建一个下载服务时&#xff0c;您可以设置一个视图来处理文件下载请求&#xff0c;并根据您的需求提供文件下载链接。以下是一个简单的示例&#xff0c;演示如何在Django中实现基本的文件下载服务&#xff1a; 创建Django项目和应用&#xff1a; 首先&#xff0c…...