IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 【JS】把Promise手写明白! -> 正文阅读

[JavaScript知识库]【JS】把Promise手写明白!


就是说,把这个最爱考的手写系列给它整明白!总结加理解加多复习,我就不信还能有什么别的花样!

先介绍一下promsie的特点,三个状态pending、reject、fullfilled(resolved),状态只能从pending到另外两个,一经生成不可再改变,然后具有.then、.finally、.all、.race等函数进行使用

  • 抽象表达:

    Promise 是一门新的技术(ES6 规范)
    Promise 是 JS 中进行异步编程的新解决方案
    备注:旧方案是单纯使用回调函数

  • 具体表达:

    从语法上来说: Promise 是一个构造函数
    从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/
    失败的结果值

  • 为何要用promsie?
    1、指定回调函数的方式更加灵活
    2、支持链式调用,解决回调地狱的问题
    在这里插入图片描述

//一个普通的promise的使用

const p = new Promise((resolve,reject) => {
    setTimeout(() => {
        let n = Math.random()*100;
        if(n < 30){
            resolve(n);
        }else{
            reject('errrro发生错误');//返回的是一个prmise对象,且状态设置为失败,值为n
        }
    },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对象
// 例1
var promise = new Promise((resovle,reject)=>{
    
})

promise.then(resolve=>{},reject=>{})

这种情况,当状态为pending的时候,要把then里面的回调函数保存起来,所以需要一个callbacks数组,等prmsie里面的resolve或足额reject之后再执行;

那么then函数是如何把传入的回调收集起来的,就是叛党当前promsie的状态是否为pending

举一个例子

// 例2
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;//返回的就是res(num),状态为resolved、值为num的promise
}

my_print(123).then((res) =>{
    console.log(res);
} )


2、间隔1s一次打印出1、2、3

//实现隔1s分别输出1、2、3
//这个感觉用async更简单,试一试

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();
//定时器+timer

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超时?

//promise设置请求超时处理
//思路是使用race这个api,同时开启定时器和请求这两个异步任务,如果定时器的timeoutdaoda
//之后请求还没有返回,就看作请求超时

//promise.race[req,timer];

//定义一个超时函数方法

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);
        }
    })
}

//整合方法,采用race进行超时请求处理

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
},
]
//利用promise控制最大并发数
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、最大并发

//promiseList=[],promise   ,n,number,最大n个并发;

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是宏仁务,所以宏仁务先执行下,

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 01:02:48  更:2022-09-04 01:06:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:41:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码