Promise

作者: 渚清与沙白 | 来源:发表于2023-11-07 15:41 被阅读0次

    Promise是JS中进行异步编程的新解决方案,Promise本质是构造函数。

    • 优点
      可以对异步任务进行封装,可以获取异步任务中的结果值
      支持链式调用,可以解决回调地狱问题
      指定回调函数更加灵活
    异步编程方式
    1. fs 文件操作
    require('fs').readFile('file.txt', 'utf8', function (err, data) {
      if (err) {
        return console.log(err);
      }
      console.log(data);
    });
    
    1. 数据库操作

    2. AJAX

    $.get('http://www.baidu.com', function (data) {
      console.log(data);
    });
    
    1. 定时器
    settimeout(function () {
      console.log('Hello');
    }, 3000);
    

    Promise

    Promise的参数excutor是一个有两个参数的函数(resolve reject)
    then函数有2个参数,第一个成功的回调函数,第二个失败的回调函数

    • 对异步任务的封装
    new Promise(function (resolve, reject) {
      // 异步操作
      setTimeout(function () {
        let a = 10;
        if(a > 5){
            resolve();
        }else{
            reject();
        }
      }, 3000);
    }).then(function () {
      console.log('成功了');
    },function(){
        console.log('失败了');
    });
    
    • 获取异步任务中的数据
    new Promise(function (resolve, reject) {
      // 异步操作
      setTimeout(function () {
        let a = 10;
        if(a > 5){
            resolve(a);
        }else{
            reject('值太大');
        }
      }, 3000);
    }).then(function (data) {
      console.log(data);
    },function(err){
        console.log(err);
    }
    
    promise风格util.promisify(original)
    const util = require('util')
    const fs = require('fs')
    let mineReadFileAsync = util.promisify(fs.readFile)
    
    mineReadFileAsync('test.txt', 'utf8').then(data => {
      console.log(data)
    }).catch(err => {
      console.log(err)
    })
    
    Promise执行流程
    未命名文件(1).jpg
    Promise的属性
    • Promise的状态改变 PromiseStatus

      1. pending 等待态:pending状态的promise既不会被执行resolve()也不会被reject()
      2. fulfilled 成功态: 执行resolve()会改变状态为 fulfilled 状态
      3. rejected 失败态:执行reject()会改变状态为 rejected 状态
        Promise的状态只有2种改变,而且只能改变一次。1. pending 变为 fulfilled 2. pending 变为 rejected。
    • Promise对象的值 PromiseResult
      PromiseResult保存异步任务 成功 | 失败 的结果值

    Promise API
    1. Promise构造函数 Promise(excutor)
      excutor是执行器
      Promise构造函数传递的执行器函数内部是同步调用的,该函数不会进入队列
    new Promise((resolve, reject) => {
        // 同步调用
        console.log('1')
    })
    console.log('2')
    // 执行结果: 1 2
    
    1. Promise.prototype.then
      返回一个新的Promise对象
    2. Promise.prototype.catch
      只能指定失败的回调,不能指定成功的回调
      catch函数做了独立的封装,内部也是调用Promise.prototype.then实现的
    3. Promise.resolve
      返回一个成功的promise对象,作用是为了快速得到一个promise对象

    4.1 如果参数传递是一个非Promise对象,则返回的结果为成功的promise对象

    Promise.resolve(1).then(function(value){
        console.log(value)// 1
    })
    

    4.2 如果参数传递是一个Promise对象,这个参数对象的结果决定了Promise的结果是失败还是成功

    let promise1 = new Promise((resolve,reject)=>{
        resolve('OK')// 返回成功
    });
    // promise2 是一个成功的promise对象,promise2的结果由 promise1的成功与失败结果 决定
    let promise2 = Promise.resolve(promise1);
    
    1. Promise.reject
      快速返回一个失败的promise对象,无论传入什么参数,他的结果始终都是失败的
    2. Promise.all
      参数是一个promise对象的【数组】,返回一个新的promise对象
      等待所有promise对象都成功才会成功,只要有一个promise对象返回失败,整个数组的promise都会失败
    3. Promise.race
      参数传递【数组】
      返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态
    常见问题
    1. 如何修改promise的状态
      1.1 调用resolve函数,将promise的状态从pending变为fulfilled
      1.2 调用reject函数,将promise的状态从pending变为rejected
      1.3 抛出错误 throw ‘Error’,将promise的状态从pending变为rejected

    2. 指定多个then回调函数,这些回调都会调用吗
      当Promise状态改变的时候,对应的回调函数都会调用

    new Promise((resolve, reject) => {
        resolve('OK')
    }).then(function (value) {
        console.log(value)//这里会执行
    }).then(function (value) {
        console.log(value)// 这里会执行
    })
    
    1. 改变promise状态和指定回调函数谁先谁后?
      都有可能,正常情况先指定回调再改变状态,但也可以先改变状态再指定回调。

    3.1 先改变状态再指定回调,then执行时就会调用回调函数

    let promise = new Promise((resolve, reject) => {
        // 同步任务
        resolve('OK')
    })
    promise.then(function (value) {
        console.log(value)
    })
    

    3.2 先指定回调再改变状态,状态改变后才会执行then中的回调函数

    let promise = new Promise((resolve, reject) => {
        // 异步任务
        settimeout(() => {
            resolve('OK')
        }, 1000)
    })
    promise.then(function (value) {
        console.log(value)
    })
    
    1. then函数返回新的promise对象的状态由什么来决定?
      由then()指定的回电函数执行的结果决定。
      (1) 回调函数抛出错误throw,结果是失败状态
      (2) 回调函数返回结果是非Promise类型对象,结果是成功状态
      (3) 回调函数返回的是Promise对象,结果就是这个返回的Promise对象的状态
    let promise = new Promise((resolve, reject) => {
        resolve('OK')
    })
    let result = promise.then(function (value) {
        throw new Error('Error')
    }).then(value =>{
        // 1. 抛出错误
        // throw '出错';
        // 2. 返回非Promise对象
        // return 100;// result的状态为成功,值为100
        // 3. 返回Promise对象
        return new Promise((resolve,reject)=>{
            // resolve(200); // result的状态为成功,值为200
            reject('出错了'); // result的状态为失败,值为出错了
        })
    },reason =>{
        console.log(reason)
    })
    
    1. 如何串联多个任务?链式调用
    new  Promise((resolve, reject) => {
        resolve('OK')
    }).then(function (value) {
        return new Promise((resolve, reject) => {
            resolve('success')
        })
    }).then(function (value) {
        // value 的结果由第一个then的结果决定
        console.log(value)// value is success
    }).then(function (value) {
        // value 的结果由第二个then的结果决定,第二个then没有写,则返回值就是undefined,是非promise类型.
        // 所以第二个then的结果是成功状态的Promise,值是undefined
        console.log(value)// value is undefined
    })
    
    
    1. 异常穿透 catch
      在最后指定失败的回调,前面任何操作出异常,都会穿透到最后一个失败的回调

    2. 如何中断promise链
      在中间中断,不会调用后面的回调函数;只有返回一个pending状态的promise对象,才会中断执行后面的回调函数

    new  Promise((resolve, reject) => {
        resolve('OK')
    }).then(function (value) {
        return new Promise(()=>{}); // 中断promise链
    }).then(function (value) {
        console.log(value)// 不会执行,只有第一个then的结果状态改变才会执行
    }).then(function (value) {
        
        console.log(value)// 不会执行
    })
    
    模拟实现Promise
    
    // 自定义封装
    function Promise(excutor) {
        // 添加属性
        this.PromiseStatus = 'pending';
        this.PromiseResult = null;
        // 保存实例对象的this的值
        const self = this;
        // 保存then的回调函数的参数,便于异步任务改变状态调用回调
        this.callbacks = [];// 类型为对象时,指定多个then回调,会覆盖,无法实现链式调用,需要使用数组
    
        // 改变状态、设置对象结果值
        function resolve(data) {
            // 保证状态只能修改一次
            if(self.PromiseStatus !== 'pending'){
                return;
            }
            // 1. 修改状态 (PromiseStatus)
            self.PromiseStatus = 'fulfilled';
    
            // 2. 设置对象结果值 (PromiseResult)
            self.PromiseResult = data;
    
            setTimeout(() => {
                // 3. 触发回调函数
                self.callbacks.forEach(callback => {
                    callback.onResolved && callback.onResolved(data);
                });
            });
            
        }
        function reject(data){
            if(self.PromiseStatus !== 'pending'){
                return;
            }
            // 1. 修改状态 (PromiseStatus)
            self.PromiseStatus = 'rejected';
    
            // 2. 设置对象结果值 (PromiseResult)
            self.PromiseResult = data;
    
            setTimeout(()=>{
                // 3. 触发回调函数
                callback.onRejected && callback.onRejected(data);
            });
        }
        // 处理抛出异常改变状态 throw error
        try {
            // 同步调用执行器函数
            excutor(resolve, reject);
        } catch (error) {
            // 修改promise对象状态为失败
            reject(error);
        }
        
    }
    
    
    Promise.prototype.then = function (onResolved, onRejected) {
        const self = this;
        // 异常穿透 判断回调参数  onRejected 没传 默认返回值
        if (typeof onRejected !== 'function') {
            onRejected = function (value) {
                return value;
            }
        }
        // 不传就默认返回
        if (typeof onResolved !== 'function') {
            onResolved = function (value) {
                return value;
            }
        }
    
        // then需要返回一个Promise对象
        return new Promise((resolve, reject) => {
            function callback(type){
                try {
                    let result = type(self.PromiseResult);
                    // 根据then的返回结果的状态进行不同的处理
                    if(result instanceof Promise){
                        result.then(data => {
                            resolve(data);
                        }, error => {
                            reject(error);
                        })
                    }else{
                        // 结果的对象状态为成功
                        resolve(result);
                    }
                } catch (e) {
                    reject(e);
                }
            }
    
            // this指向实例对象,因为是实例对象在调用这个方法
            if(this.PromiseStatus === 'fulfilled'){
                // 保证then的回调是异步执行
                setTimeout(() => {
                    callback(onResolved);   
                });
            }else if(this.PromiseStatus ==='rejected'){
                setTimeout(() => {
                    callback(onRejected);   
                });
            }else if(this.PromiseStatus ==='pending'){
                // pending状态 异步任务 延时执行改变状态
                // 保存回调函数 在状态改变时进行调用
                this.callbacks.push({
                    onResolved: function () {
                        callback(onResolved);
                    },
                    onRejected: function () {
                        callback(onRejected);
                    }
                })
            }
        })
    }
    
    // 添加捕获错误方法
    Promise.prototype.catch = function (onRejected) {
        return this.then(undefined, onRejected);
    }
    
    // 添加resolve方法
    Promise.resolve = function (value) {
        return new Promise(function (resolve,reject) {
            if(value instanceof Promise) {
                value.then(v=>resolve(v),e=>reject(e))
            }else {
                resolve(value)
            }
        })
    }
    
    // 添加reject方法
    Promise.reject = function (reason) {
        return new Promise(function (resolve,reject) {
            reject(reason)
        })
    }
    // 添加all方法
    Promise.all = function (promises) {
        return new Promise(function (resolve,reject) {
            let result = []
            let count = 0
            for(let i = 0;i<promises.length;i++) {
                promises[i].then(function (value) {
                    // 这里可以得知对象的状态是成功
                    result[i] = value // 结果的顺序是按照promise的顺序来的
                    count++
                    if(count === promises.length) {
                        resolve(result)
                    }
                })
               .catch(function (reason) {
                    reject(reason)
                })
            }
        })
    }
    // 添加trace方法
    Promise.race = function (promises) {
        return new Promise(function (resolve, reject) {
            for(let i = 0; i < promises.length; i++) {
                promises[i].then(function (value) {
                    resolve(value) // 第一个成功的promise执行resolve 决定race的结果
                })
               .catch(function (reason) {
                    reject(reason)
                })
            }
        })
    }
    

    async 与 await

    async函数

    【async函数】返回一个 Promise 对象,可以使用 then 方法添加回调函数。Promise的对象结果是由async函数的返回值来决定的

    async function main() {
        // 返回一个非 Promise类型的数据,main函数的返回值是一个成功的Promise对象
       return  1;
       // 返回一个 Promise 对象,main函数的返回值由Promise.resolve()方法返回的Promise对象决定状态
       return  Promise.resolve(1);
    }
    
    await

    await右侧是一个Promise对象,await 返回的是Promise成功的值。
    await右侧是其他值,直接将此值作为wait的返回值。
    await必须写在async函数内部,但是async内部可以没有await。
    await 右侧的promise是一个失败的promise,那么await会抛出这个错误。需要使用try...catch来捕获异常。

    async function main() {
      // 1. 右侧为Promise的情况
      let res = await Promise.resolve('OK');// OK
      // 2. 右侧为其他类型
      let res2 = await 123; // 123
      // 3. 右侧为失败的Promise
      try {
        let res3 = await Promise.reject('error');
      }catch(e){
        console.log(e);// error
      }
    }
    

    相关文章

      网友评论

          本文标题:Promise

          本文链接:https://www.haomeiwen.com/subject/ozhxwdtx.html