• promise详解


    /**
    * 浅谈 Promise
    * 问题:怎么理解的?:Promise是什么,做什么的,有啥问题,有啥解决办法
    */

    /**
    * 1、Promise是一种异步编程的解决方案,用于解决回调地狱的问题
    * 是构造函数,可以理解为是一个容器,里面是异步事件;
    */

    /**
    * 2、
    * 特点:
    * 1、Promise对象的状态不受外界影响,三种状态:pending(初始状态)、fulfilled(成功)、rejected(失败);
    * 2、状态改变后不再改变,状态不可逆,只能pending到fulfilled,或者pending变成rejected;
    * 缺点:
    * 1、无法取消Promise,一旦建立无法取消;
    * 2、如果不设置回调函数,Promise内容出错,不会反映到外部;
    * 3、处于pending状态,无法得知是处于了哪一个阶段,是刚开始,还是快结束了;
    */

    /**
    * 3、Promise的方法 && 简单实现 && axios的实现
    * Promise.then()、Promise.catch()、Promise.finally()
    */

    // 1、Promise.resolve(value)方法返回一个以给定值解析后的Promise 对象
    Promise.resolve('success').then((res) => {
    console.log(res); // success
    }, (res) => {
    // 不会被调用
    })

    // 2、Promise.reject(reason)方法返回一个带有拒绝原因reason参数的Promise对象
    Promise.reject('failed').then((res) => {
    // 不会被调用
    },(res) => {
    console.log(res); // failed
    })

    // 3、Promise.race(iterable)方法返回一个promise,一旦迭代器中的某个promise解决或者拒绝,返回的promise就会解决或者拒绝
    let p1 = new Promise((resolve, reject) => { setTimeout(()=>{resolve('one')}, 1000) })
    let p2 = new Promise((resolve, reject) => { setTimeout(()=>{resolve('two')}, 100) })
    Promise.race([p1, p2]).then((res) => { console.log(res) });
    // two , p2先执行

    // 4、Promise.all()方法返回一个Promise实例,接受一个数组(里面都是Promise实例)作为参数,等待所有都成功才会返回成功,或者其中有一个失败则返回失败,且返回该失败的回调;

    Promise.all = (promise) => {
    return new Promise((resolve, reject) => {
    let result = [], index = 0;
    if(promise.length === 0){
    resolve(result);
    }else{
    for (let i = 0; i < promise.length; i++) {
    Promise.resolve(promise[i]).then((res) => {
    result[i] = res;
    // 因为then是异步任务,所以需要另加index
    if(++index === promise.length) resolve(result);
    }, error => {
    reject(error);
    return;
    })
    }
    }
    })
    }

    /**
    * Promise 实现 Polyfill
    */
    class Rpromise {
    constructor(excutor) {
    this.status = 'pending'; // 实例状态
    this.fulfilledCallbacks = []; // 成功状态事件池
    this.rejectedCallbacks = []; // 失败状态事件池
    this.value = undefined; // 记录resolve和reject时候的参数
    const resolve = (result) => {
    // 如果不是pending那么状态已经不能更改了
    if(this.status === 'pending'){
    this.status = 'resolved';
    this.value = result;
    // 为了避免还没有执行then,成功状态事件池还没有添加这里就同步执行了,因为forEach是同步方法
    // 所以需要把循环事件池处理成异步的,考虑到then也是异步的,所以不仅要将这里处理成异步的
    // 还要这里的异步在then后执行,then是微任务,加定时器变成宏任务,在then后执行
    let time = setTimeout(() => {
    clearTimeout(time);
    // 循环执行成功状态事件池中的事件
    this.fulfilledCallbacks.forEach(item => item(this.value));
    }, 0);
    }
    }
    const reject = (res) => {
    if(this.status === 'pending'){
    this.status = 'rejected';
    this.value = res;
    let time = setTimeout(() => {
    clearTimeout(time);
    this.rejectedCallbacks.forEach(item => item(this.value));
    }, 0);
    }
    }

    try {
    excutor(resolve, reject);
    } catch (error) {
    reject(error);
    }
    }

    then(onFulfilled, onRejected){
    // 需要链式调用then方法,所以then方法的返回值必须是一个promise的实例,而resolve和reject
    // 两个形参则是用来改变返回的这个promise的状态的,因为下一个then中的回调还挂着返回这个promise
    // 对象的身上,需要通过控制resolve和reject的执行来控制下一个then中执行的方法
    return new Rpromise((resolve, reject) => {
    if(this.status === 'resolved'){
    // 向成功状态事件池添加回调,只添加并没有执行,this指向上一个promise实例,
    // 什么时候执行?在调用this的resolve方法时被执行,result就是传进来的this.value
    this.fulfilledCallbacks.push((result) => {
    // 如果then中的方法执行时报错,直接执行返回的promise的reject方法触发下一个then的失败回调执行
    try {
    let res = onFulfilled(result);
    if(res instanceof Rpromise){
    res.then(resolve, reject);
    }else{
    resolve(res);
    }
    } catch (error) {
    reject(error);
    }
    })
    }
    if(this.status === 'rejected'){
    this.rejectedCallbacks.push((result) => {
    try {
    let res = onRejected(result);
    if(res instanceof Rpromise){
    res.then(resolve, reject);
    }else{
    reject(res)
    }
    } catch (error) {
    reject(error);
    }
    })
    }
    })
    }
    }

    /**
    * 用Promise实现 axios
    * 1、创建XMLHttpRequest对象
    * 2、使用open函数
    * 3、设置onreadystatechange回调
    * 4、send请求数据
    */
    function axios(params) {
    const {url, method, data} = params;
    return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onreadystatechange = () => {
    if(xhr.readyState !== 4) return;
    if(xhr.statue === 200){
    resolve(xhr.response);
    }else{
    reject(xhr.statusText);
    }
    }
    xhr.send(data);
    })
    }


    /**
    * 4、Promise的痛点解决
    * 1、无法取消Promise, 使用async/await 可以return终止
    * 2、不设置回调出错不会反映到外部,使用async/await 可以每个阶段return Promise.reject(new Error('拒绝'))
    */

    // async声明的函数的返回本质上是一个Promise
    // async是一个关键字,表示异步

    function timeout(ms) {
    return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, "finish");
    });
    }

    timeout(2000).then(value => {
    console.log("第一层" + value); return timeout(2000);
    }).then(value => {
    console.log("第二层" + value); return timeout(2000);
    }).then(value => {
    console.log("第三层" + value); return timeout(2000);
    }).then(value => {
    console.log("第四层" + value); return timeout(2000);
    }).then(value => {
    console.log("第五层" + value); return timeout(2000);
    }).catch(err => {
    console.log(err);
    });

    // 改用 async
    async function asyncTimeSys(){
    await timeout(1000);
    console.log("第一层异步结束!")
    await timeout(1000);
    console.log("第二层异步结束!")
    await timeout(1000);
    console.log("第三层异步结束!")
    await timeout(1000);
    console.log("第四层异步结束!")
    await timeout(1000);
    console.log("第五层异步结束!")
    return "all finish";
    }
    asyncTimeSys().then((value)=>{
    console.log(value);
    });

    // 误区 :await并不是是把同步变为异步
    // async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,
    // 等到触发的异步操作完成,再接着执行函数体内后面的语句
    async function async1(){
    console.log('async1 start')
    await async2();
    console.log('async1 end')
    }
    async function async2(){
    console.log('async2')
    }
    async1();
    console.log('i am koala')
    console.log(timeout())
    // async1 start
    // async2
    // i am koala
    // async1 end
    // 简单的说,先去执行后面的同步任务代码,执行完成后,
    // 也就是表达式中的 Promise 解析完成后继续执行 async 函数并返回解决结果
  • 相关阅读:
    客户端用mstsc不能用一台设备连接终端服务器的解决办法
    [转]知识管理ABC
    Visual Studio常用小技巧[备忘]
    一套外企的数据库设计面试题
    MSDN中的图形元素和文档约定[备忘]
    设计模式概述
    ASP.Net 4.0中新增加的23项功能[转]
    Dreamweaver 8 的相关使用
    浅谈ThreadPool 线程池
    C#委托的异步调用[学习]
  • 原文地址:https://www.cnblogs.com/fmixue/p/12013838.html
Copyright © 2020-2023  润新知