就是说,把这个最爱考的手写系列给它整明白!总结加理解加多复习,我就不信还能有什么别的花样!
先介绍一下promsie的特点,三个状态pending、reject、fullfilled(resolved),状态只能从pending到另外两个,一经生成不可再改变,然后具有.then、.finally、.all、.race等函数进行使用
-
抽象表达: Promise 是一门新的技术(ES6 规范) Promise 是 JS 中进行异步编程的新解决方案 备注:旧方案是单纯使用回调函数 -
具体表达: 从语法上来说: Promise 是一个构造函数 从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/ 失败的结果值 -
为何要用promsie? 1、指定回调函数的方式更加灵活 2、支持链式调用,解决回调地狱的问题
const p = new Promise((resolve,reject) => {
setTimeout(() => {
let n = Math.random()*100;
if(n < 30){
resolve(n);
}else{
reject('errrro发生错误');
}
},1000)
})
console.log(p)
p.then((value) => {
console.log('成果'+value)
},(err) => {
console.log('shibai'+err)
})
所以手写的就要实现基本的功能,一个构造promise,resolve、reject回调函数,返回promise还要支持then的调用
手写Promsie函数
const promiseA = new Promise( (resolve,reject) => {
resolve(777);
});
- 传入了一个函数,而且这个函数被立即执行,不仅如此,这个函数还会立即执行resolve和reject。说明构造函数里有resolve和reject方法。因此我们可以初步实现:
- 每个promise都有一个状态可能为pending或resolved,rejected。而且初始状态都为pending。因此需要添加个status来表示当前promise的状态.。并且每个promise有自己的data。
- 不管是Promise原型对象上的方法还是Promise函数对象上的方法 ,它们的执行结果都将返回一个Promise对象
var promise = new Promise((resovle,reject)=>{
})
promise.then(resolve=>{},reject=>{})
这种情况,当状态为pending的时候,要把then里面的回调函数保存起来,所以需要一个callbacks数组,等prmsie里面的resolve或足额reject之后再执行;
那么then函数是如何把传入的回调收集起来的,就是叛党当前promsie的状态是否为pending
举一个例子
var promise = new Promise((resolve,reject)=>{
setTimeout(function () {
resolve(1)
})
})
promise.then(
value=>{console.log(value)},
err=>{console.log(err)}
)
- 先执行new Promise里的代码,然后发现个定时器,js线程将定时器交给定时器线程处理,2. 然后继续执行下面的代码,发现是then,而且当前的promise还是pending的状态。就把then里的回调函数放到callbacks中。
- 5秒后定时器线程将定时器里的回调函数(也就是宏任务)放到消息队列中,js线程在消息队列里发现了这个宏任务,就把它拿来执行。- - 执行这个宏任务,就执行了resolve(1),此时promise的callbacks里的回调被执行。并将当前promise状态改为resolved。然后这个1也会被 保存到当前promise对象中
那怎么实现resolve呢?依旧上面的描述,就知道resovle的功能是执行callbacks里的函数,并保存data,并将当前promise状态改为resolved。所以我们可以这么实现
执行到then时,promise可能会是pending状态,此时就要把then里的回调函数保存起来,也可能会是resolved或者rejected状态,此时就不用把回调保存起来,直接执行onResolved或onRejected方法。注意是异步执行。而且是做为微任务的,这里我们简单的用setTimeout来实现就好了。
function Promsie(callback) {
this.state = PENDING;
this.value = null;
this.resolvedCallbacks = []
this.rejectedCallbacks = []
callback(value => {
if(this.state == PENDING){
this.state = RESOLVED
this.value = value
this.resolvedCallbacks.map(callback => callback(value))
}
},value => {
if(this.state === PENDING){
this.state = REJECTED;
this.value = value;
this.rejectedCallbacks.map(callback => callback(value))
}
})
}
Promise.prototype.then = function(onFulfilled= () => {},onRejected =()=> {})
{
if(this.state === PENDING){
this.resolvedCallbacks.push(onFulfilled)
this.rejectedCallbacks.push(onRejected)
}
if(this.state === RESOLVED){
onFulfilled(this.value);
}
if(this.state === REJECTED){
onRejected(this.value);
}
}
手写Promsie.then
手写Promise.all
Promise.myall = function(promiseArr){
return new Promise((resolve,reject) => {
const ans = [];
let index = 0;
for(let i = 0; i < promiseArr.length; i ++){
promiseArr[i].then(res => {
ans[i] = res;
index++;
if(index === promiseArr.length){
this.resolve(ans);
}
}).catch(err => reject(err));
}
}
)
}
手写Promise.race
Promise.myrace = (promiseArr) => {
return new Promsie((res,err) => {
promiseArr.forEach((p) => {
p.then(res=>{
resolve(p);
},err => {
reject(err);
})
})
})
}
Promise的应用系列
1、定时3s打印出1
function my_print(num){
let three = new Promise((res,err) => {
setTimeout(() => {
res(num)
},1000);
})
return three;
}
my_print(123).then((res) =>{
console.log(res);
} )
2、间隔1s一次打印出1、2、3
const printOne = (num) => {
let ans = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(num);
resolve(num)
},2000)
})
return ans;
}
let interval = async() => {
await printOne(1);
await printOne(2);
await printOne(3);
}
interval();
async function timer(n) {
for(let i = 1; i < n; i++){
console.log('ww',await _promise(i,i*1000))
}
}
function _promise(num,interval){
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve(num)
},interval)
})
}
3、promise并发
4、promise超时?
function defineTimeout(time){
return new Promise((resolve,reject) => {
setTimeout(() => {
reject("请求超时!");
cancelXhr();
},time);
})
}
function myRequest(config){
return new Promise((resolve,reject) => {
const xhr = new XMLHttpRequest();
xhr.open(config.method,config.url);
xhr.send();
cancelXhr = () => {
xhr.abort();
}
xhr.onload = () => {
resolve(xhr.responseText);
}
xhr.onerror = () => {
reject(xhr.statusText);
}
})
}
function myovertime(config,time){
return Promise.race([myRequest(config),defineTimeout(time)]).then(res => {
console.log('请求成果!' + res);
}).catch(err => {
console.log('请求失败' + err);
})
}
let config = {
method:"GET/POST",
url:"接口地址"
}
myovertime(config,2000);
5、利用promise控制最大并发数
const urls = [{
info: 'link1',
time: 3000
},
{
info: 'link2',
time: 2000
},
{
info: 'link3',
time: 5000
},
{
info: 'link4',
time: 1000
},
{
info: 'link5',
time: 1200
},
{
info: 'link6',
time: 2000
},
{
info: 'link7',
time: 800
},
{
info: 'link8',
time: 3000
},
]
function loadImg(url){
return new Promise((resolve,reject) => {
console.log('---' + url.info+'start');
setTimeout(() => {
console.log(url.info + 'ok!!!')
resolve()
},url.time);
})
}
function promiseLimit(arr,maxCount){
let current = 0;
let pendingList = [];
for(let i = 0; i < arr.length; i++){
doSend(arr[i]);
}
function doSend(item){
if(current < maxCount){
current++;
loadImg(item).then(() => {
current--;
if(pendingList.length > 0){
doSend(pendingList.shift())
}
})
}else{
pendingList.push(item)
}
}
}
promiseLimit(urls,3)
promiseLimit(urls,2);
6、在限制最大并发数的同时,任务优先级别高的先执行
7、最大并发
const p1 = new Promise(r => {
setTimeout(() => {
console.log('p1', new Date());
r('');
}, 1000);
});
const p2 = new Promise(r => {
setTimeout(() => {
console.log('p2', new Date());
r('');
}, 3000);
});
const p3 = new Promise(r => {
setTimeout(() => {
console.log('p3', new Date());
r('');
}, 1000);
});
const p4 = new Promise(r => {
setTimeout(() => {
console.log('p4', new Date());
r('');
}, 2000);
});
const p5 = new Promise(r => {
setTimeout(() => {
console.log('p5', new Date());
r('');
}, 2000);
});
const promiseList = [p1, p2, p3, p4];
const n = 3;
let count = 0;
let pendingList = [];
function maxPromise(promiseList,n){
for(let i = 0;i < promiseList.length; i++){
operate_promise(promiseList[i],n) };
}
function operate_promise(promiseA,n){
if(count >= n){
pendingList.push(promiseA);
}else{
count++;
pendingList.shift().then(()=>{
count--;
if(pendingList.length){
operate_promise(pendingList.shift())
}
})
}
}
promise异步输出题,经典
答案 2 4 7 5 3 6 async2的结果 1
1、8肯定不执行,promise没有没有resolve和reject 2、script是宏仁务,所以宏仁务先执行下,
|