流年似水博客开通了,本站主要是写关于Web和大数据方面内容,正在更新中,欢迎大家光临!
  1. 文章:97 篇
  2. 总浏览:35,079 次
  3. 评论:22条
  4. 最后更新:2020-06-08
  5. 分类目录:39 个

一篇文章让你吃透Promise(上篇)

Javascript l, xy 219℃ 0评论

前言:

本文章最终目的是实现自定义promise。详细罗列了实现自定义promise的理论知识、promise特性,充分了解Promise,并且实现一个几乎接近原生的自定义Promise。个人见识有限,如有差错,请多多见谅

参照MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

一、自定义promise知识储备

1、函数对象与实例对象

   function Fn(){}
   var fn = new Fn(); //Fn:构造函数 , fn:实例对象(new 函数产生的对象)
   Fn.prototype //当前Fn是函数对象(将函数作为对象使用时,称为函数对象)

2、两种类型的回调函数

        2.1、同步回调

            遍历回调,同步回调函式,不会放入对列中,一上来就会执行完
   [1,2,3,4].forEach(item=>{
       console.log(“同步")
   })
   console.log(“forEach结束")

        2.2、异步回调

            异步回调放入对列中,将来执行
   setTimeOut(()=>{//先将函数放入对列
       console.log(“异步”)
   },0)
   console.log(“setTimeOut结束")

二、什么是Promise(面试可能用到哦)

    1、抽象说法:

        Promise是js中进行异步编程的新的解决方法(旧的:纯回调)
    2、具体说法:
        1>语法上说:Promise是构造函数
        2>功能上说:Promise对象是封装一个异步操作并返回其结果
    3、状态:
    pending变成fulfilled
    pending变为rejected
    
    注:状态只能改变一次
            fulfilled的结果常常使用value表示,rejected的结果常常使用reason表示。

三、为什么要使用Promise

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

            旧的执行方法:必须在异步启动任务之前定义回调函数
            Promise:同步回调,异步启动=>返回promise 对象=>给promise绑定回调函数(甚至可以在异步任务完成后再绑定)
        2、支持链式调用,可以解决回调地狱的问题

            回调地狱?回调函数嵌套调用,函数的返回值将作为下一个回调函数的参数使用。(非常不便于阅读) 

    回调地狱实例:

    
    //普通处理回调地狱,
    function faultFn(err) {
        console.log("执行失败", err)
    }
    function doSomeFn(cb, faultFn) {
        try {
            cb && cb(1);
            return 1;
        } catch (error) {
            faultFn && faultFn(error);
        }
    }
    function doSomeFn2(params, cb, faultFn) {
        try {
            params += 2
            cb && cb(params);
            return params;
        } catch (error) {
            faultFn && faultFn(error);
        }
    }
    function doSomeFn3(params, cb, faultFn) {
        try {
            params += 3
            cb && cb(params);
            return params;
        } catch (error) {
            faultFn && faultFn(error);
        }
    }
    doSomeFn(function sFn(result) {
        doSomeFn2(result, function sFn(params1) {
            doSomeFn3(params1, function sFn(params2) {
                console.log("最终执行结果----", params2)
            }, faultFn);
        }, faultFn);
    }, faultFn);
   //promise实现
   new Promise((reslove, reject) => {
         reslove(doSomeFn())
   }).then(val => {
         return doSomeFn2(val);
   }).then(val => {
        return doSomeFn3(val)
   }).then(val => {
        console.log("value3=======", val);
   }).catch(err => {
        faultFn(err)
   })

四、Promise的几个关键问题

1、创建promise的两种方式

    
    let p1 = new Promise((res, rej) => {
    res(1)
    })
    let p2 = Promise.resolve(2); //new promise的语法糖
    let p3 = Promise.resolve(3);

2、如何改变promise对象状态?

  • 调用reslove()方法,pending=>resolved

  • 调用reject()方法,pending=>rejected

  • Throw抛出异常,pending=>rejected

3、定义多个promise成功/失败函数都能调用吗?

    当promise状态改变,指定的对应成功/失败函数将都会执行。
    
    let p1 = new Promise((res, rej) => {
        res(1)
    })
    p1.then(value => {
        console.log("resolved1=========", value)
    }, reason => {
        console.log("rejected1========", reason)
    })
    p1.then(value => {
        console.log("resolved2=========", value)
    }, reason => {
        console.log("rejected2========", reason)
    })
    /*执行结果:resolved1========= 1
    resolved2========= 1*/

4、指定回调函数和改变状态哪个先执行

两种情况:

  • 普通情况,先指定回调函数,再改变状态

        
    let p1 = new Promise((res, rej) => {        
        setTimeout(()=>{
            res(1) //改变状态
        },1000)
    })
    p1.then(value => {
        console.log("resolved1=========", value)
    }, reason => {
        console.log("rejected1========", reason)
    })

  • 先改变状态,再指定回调函数

    
    let p1 = new Promise((res, rej) => {
        res(1) //改变状态
    })
    p1.then(value => {
        console.log("resolved1=========", value)
    }, reason => {
        console.log("rejected1========", reason)
    })

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

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

  • 如果抛出异常,新promise将变为rejected,reason为抛出的异常。
  • 如果返回的是非promise的任意值,新promise状态变为resloved,value为返回值。
  • 如果返回的是另一个promise,此promise的结果就会是新的promise的结果值。
    举例(2)最后一条
    let p1 = new Promise((res, rej) => {
        res(1)
    })
    p1.then(value => {
        console.log("resolved1=========", value)
        return Promise.reject(2);
    }, reason => {
        console.log("rejected1========", reason)
    }).then(value => {
        console.log("resolved2=========", value)
    }, reason => {
        console.log("rejected2========", reason)
    })
    /*执行结果:resolved1========= 1
          rejected2======== 2
      此时状态变为reject并且reasion为2
    */

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

  •     Promise.then将返回一个新的promise, 可以开始then的链式调用
  •     then链式调用可以串联多个同步/异步任务

证明then返回的是新的promise:
    let p1 = new Promise((res, rej) => {
        res(1)
    })
    p1.then(value => {
        console.log("resolved1 = ", value, "; 原始promise = ", p1)
        return 2;
    }).then(value => {
        console.log("resolved2 = ", value, "; 原始promise = ", p1)
    })
    返回结果:
image-15878739679404_false.webp
    resolved2的value=2,但是原始promise(即p1)的值还是1。
    证明 then链式调用可以调用多个异步/同步任务:
    let p1 = new Promise((res, rej) => {
        res(1)
    })
    p1.then(value => {
        console.log("同步-----", value)
        return 2;
    }).then(value => {
        return new Promise((reslove, reject) => {
            setTimeout(() => {
                console.log("异步-----", value)
                reslove(3)
            }, 1000)
        })
    }).then(value => {
        console.log("同步-----", value)
    })
执行结果:
image-15878739672085_false.webp

7、promise异常穿透?

  • 当使用promise的then链式调用时,可以在最后指定失败回调函数
  • 前面任何操作出现异常都将传递到最后失败的回调处理中
 
    let p1 = new Promise((resolve, reject) => {
        reject(1)
    })
    p1.then(value => {
        return 2;
    }).then(value => {
        console.log("最终结果-----", value)
    }).catch(reason => {
        console.log("执行失败-----", reason)
    })
    
真实的实现情况是这样的:
    let p1 = new Promise((resolve, reject) => {
        reject(1)
    })
    p1.then(
        value => 2,
        reason => { throw reason }
    ).then(
        value => {
            console.log("最终结果-----", value)
        },
        reason => { throw reason }
     ).catch(reason => {
        console.log("执行失败-----", reason)
     })

promise并不是能异常穿透,发生异常/rejected状态都将向下一级catch函数传递,若是未定义catch函数,Promise会自动添reason => { throw reason },抛出异常。并传递给下一个状态处理函数。

8、如何中断promise链?

    要求:使用promise的then链式调用时,在中间中断,不再执行后面的回调函数。
    实现:在回调函数中返回一个peding状态的的promise对象
    let p1 = new Promise((resolve, reject) => {
        reject(1)
    })
    p1.then(
        value => 2
    ).then(value => {
        console.log("最终结果-----", value)
    }).catch(reason => {
        console.log("执行失败-----", reason)
        return new Promise(() => {});
    }).then(value => {
        console.log("未中断哦,继续执行了", value)
    })

五、实现自定义Promise

一篇文章让你吃透Promise(下篇)

转载请注明:流年似水 » 一篇文章让你吃透Promise(上篇)

喜欢 (0)or分享 (0)

Warning: copy(https://cn.gravatar.com/avatar/?s=54&d=%2Fwp-content%2Fthemes%2Fyusi1.0%2Fimg%2Fdefault.png&r=g): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in /usr/share/nginx/html/timewentby/wp-content/themes/yusi1.0/functions.php on line 239

Warning: copy(/wp-content/themes/yusi1.0/img/default.png): failed to open stream: No such file or directory in /usr/share/nginx/html/timewentby/wp-content/themes/yusi1.0/functions.php on line 243
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址