08-异步新增

nobility 发布于 2023-03-17 02-ES6 458 次阅读


异步新增

Promise

Promise 有三个状态,pending挂起状态,fulfulled成功状态,rejected失败状态,这三种状态只能由挂起到成功或失败状态这两条途径,而且一旦成功或失败状态就不可更改,所以在new一个 promise 实例时只要执行了一个resolvereject之后再执行的resolvereject将毫无意义

构造方法

  • 参数必须是一个函数,否则会报错,并且该函数会立即同步执行
  • 该回调函数有两个参数resolvereject也是函数类型,这两个参数改变状态的代码由 js 引擎实现
    • resolve:代表成功的回调函数,会将该 promise 状态转化为fulfulled成功状态
      • value:该函数有一个参数用来保存成功的结果
    • reject:代表失败的回调函数,会将该 promise 状态转化为rejected失败状态,失败状态必须要处理,否则会有警告
      • reason:该函数有一个参数用来保存失败的结果
  • 抛出错误,相当于执行reject (error)

静态方法

方法名 描述
Promise.Resolve (object) 无参,则将返回一个空的且状态是成功的 promise 对象;参数若是普通值,则将该值放入一个状态为成功的 promise 对象中并返回;参数若是 promise 对象,则原封不动返回该对象;参数若是一个带有then ()方法的对象,会立即异步的执行这个then ()方法,该then ()方法中可以控制返回 promise 状态,也就是说该then ()方法也有两个函数类型参数,一个是resolvereject
Promise.Reject (reason) reason放入一个状态为rejected的 promise 对象中并返回
Promise.All (pramises) 接收一个集合,若数组元素不是 promise 对象会先调用Promise.Resolve ()方法包装成一个 promise 对象,返回一个 promise 对象,该对象的状态和值由 promises 集合中所有对象的执行结果决定,全部成功则返回的 promise 对象状态就是成功的,值就是以数组形式对应的执行结果的值,有一个失败则返回的 promise 对象状态就是失败的,值是第一个失败的结果
Promise.Race (pramises) 接收一个集合,若数组元素不是 promise 对象会先调用Promise.Resolve ()方法包装成一个 promise 对象,返回一个 promise 对象,该对象的状态和值由 promises 数中所有对象的执行结果决定,总是返回第一个完成的 promise 对象,无论是成功还是失败
Promise.AllSettled (pramises) 接收一个集合,若数组元素不是 promise 对象会先调用Promise.Resolve ()方法包装成一个 promise 对象,返回一个 promise 对象,该对象的状态为成功的 promise 对象,只不过该对象的值是将 promises 集合中每个 promise 对象的返回值都封装成了 promise 对象,这些 promise 对象的状态由上一次的执行结果决定

实例方法

方法名 描述
Promise.Prototype.Then (resolve[, reject]) resolve是成功状态的回调函数,reject是失败状态的回调函数且可省略,并且这些回调是异步执行的;返回一个新的 promise 对象,由执行这两个回调函数的返回值决定;返回一个普通值=成功的包装该值的 promise 对象,返回一个 promise 对象=该 promise 对象,抛出错误=返回一个包装该错误的 promise 对象
Promise.Prototype.Catch (reject) reject是失败的回调函数,相当于调用then (undefuned, reject)方法所以,返回的 promise 对象与then ()方法一致
Promise.Prototype.Finally (close) close是无论当前 promise 是什么状态都会执行的的回调函数,无论该回调中是有retuen语句,总是返回一个值为undefined状态为成功的 promise 对象

Promise 应用

可以达到串行执行异步任务的效果

New Promise ((resolve, reject)=>{
    SetTimeout (()=>{
        Resolve (1);
    }, 1000);
}). Then ((value)=>{
    Return new Promise ((resolve, reject)=>{
        SetTimeout (()=>{
            Resolve (value+"处理 value 后");
        }, 500)
    })
}). Then ((value)=>{
    Console.Log (value);
}). Catch ((error)=>{
    Console.Log (error);
})

Promise 原理

Const PENDING = Symbol ("pending");  //挂起状态
Const REJECTED = Symbol ("rejected");    //失败状态
Const FULFULLED = Symbol ("fulfilled");  //成功状态
/*
Promise: 构造函数,创建 promise 实例
Excutor: 执行器函数,同步立即执行
*/
Function Promise (excutor) {
  Const self = this;  //保存当前函数 this 方便在内部函数使用
  This. Status = PENDING;  //当前 promise 对象的状态,初始是 pending
  This. Data = undefined;  //存储结果数据
  This. Callbacks = [];    //回调函数队列,元素以{ onResolved (){}, onRejected (){} }形式保存
  Try { //若执行器执行抛出异常则说明该 promise 是失败的
    Excutor (resolve, reject); //立即执行执行器函数
  } catch (error) { //将抛出的错误信息当作失败回调函数的 reason
    Reject (error)
  }
  /*
  Resolve: 将当前 promise 对象状态转为 fulfilled,保存 value 到当前 promise 对象的 data 中,异步执行函数队列中成功的回调函数
  Value: 成功的结果
  */
  Function resolve (value) {
    If (self. Status !== PENDING) return;  //状态只能是从 pending 到其他状态,若已是成功或失败则不需要执行该函数
    Self. Status = FULFULLED;  //改变状态为成功 fulfilled
    Self. Data = value;  //保存 value 到 promise 的 data 中
    SetTimeout (() => {  //若在调用 resolve 之前为此 promise 对象绑定了回调函数,则依次异步执行这些回调函数
      For (let i = 0; i < self. Callbacks. Length; i++) { //遍历函数执行队列并执行成功的回调
        Self. Callbacks[i]. OnResolved ();
      }
    });
  }
  /*
  Reject: 将当前 promise 对象状态转为 rejected,保存 reason 到当前 promise 对象的 data 中,异步执行函数队列中失败的回调函数
  Reason: 失败的原因
  */
  Function reject (reason) {
    If (self. Status !== PENDING) return;  //状态只能是从 pending 到其他状态,若已是成功或失败则不需要执行该函数
    Self. Status = REJECTED; //改变状态为失败 rejected
    Self. Data = reason; //保存 reason 到 promise 的 data 中
    SetTimeout (() => {  //若在调用 reject 之前为此 promise 对象绑定了回调函数,则依次异步执行这些回调函数
      For (let i = 0; i < self. Callbacks. Length; i++) { //遍历函数执行队列并执行失败的回调
        Self. Callbacks[i]. OnRejected ();
      }
    });
  }
}
/*
Then: 为当前对象绑定回调函数,再根据回调返回值指返回一个新的 promise 对象
OnResolved: 成功的回调函数
OnRejected: 失败的回调函数
*/
Promise. Prototype. Then = function (onResolved, onRejected) {
  Const self = this;  //保存当前函数 this 方便在内部函数使用
  OnResolved = typeof onResolved === "function" ? OnResolved : value => value;  //传入参数是非函数,指定回调向下传递参数即可
  OnRejected = typeof onRejected === "function" ? OnRejected : reason => { throw reason } //省略错误回调,向下传递抛出错误,在 handle 函数中会转化为失败的 promise 达到向下传递错误的目的
  Return new Promise ((resolve, reject) => { //返回一个新的 promise 对象
    /*
    Handle: 统一处理 onResolved 或 onRejected 指定回调中抛出错误、promise 对象、普通值的情况,从而决定返回新的 promise 对象的状态
    Callback: 同步的回调函数,主要使用该回调函数的返回值指定决定新的 promise 对象的状态
    */
    Function handle (callback) {
      Try { //若执行指定回调函数抛出错误则说明该 promise 是失败的
        Const result = callback (self. Data); //取得回调函数的返回值
        If (result instanceof Promise) {  //若返回值是 promise 对象
          Result.Then (resolve, reject); //则新的 promise 对象的状态由该返回的 promise 对象的状态决定
        } else {  //若返回值是普通值则
          Resolve (result);  //则新的 promise 对象的状态是成功的
        }
      } catch (error) { //将抛出的错误信息当作失败回调函数的 reason
        Reject (error);
      }
    }
    Switch (self. Status) {
      Case PENDING: //若当前 promise 对象状态是挂起状态,也就是创建 promise 对象时,执行器中的异步操作才执行到 resolve 或 reject 回调,即先绑定后执行
        Self.Callbacks.Push ({ //将绑定的回调函数添加到回调队列上,等 promise 对象异步操作时执行 resolve 或 reject 回调再由执行器执行
          OnResolved () { handle (onResolved) },  //将处理成功的回调按照回调队列要求包装在 onResolved 中
          OnRejected () { handle (onRejected) } //将处理失败的回调按照回调队列要求包装在 onRejectedd 中
        })
        Break;
      Case FULFULLED: //若当前 promise 对象状态是成功状态,也就是创建 promise 对象时,执行器中的同步操作执行到 resolve(不严谨),即先执行后绑定
        SetTimeout (() => { handle (onResolved) });
        //先执行后绑定是不可能的,只是执行了改变状态的代码,由于执行器其实是由于回调队列中是空的,就直接跳过了执行回调队列的操作, 要在调用 then 方法绑定成功回调时时立刻异步执行
        // handle (onResolved);
        Break;
      Case REJECTED:  //同理,若当前 promise 对象的状态是失败状态,也就是创建 promise 对象时,执行器中的同步操作执行到 reject 回调(不严谨),即先执行后绑定
        SetTimeout (() => { handle (onRejected) });
        //同样的,先执行后绑定是不可能的,只是执行了改变状态的代码,由于执行器其实是由于回调队列中是空的,就直接跳过了执行回调队列的操作, 要在调用 then 方法绑定失败回调时时立刻异步执行
        // handle (onRejected);
        Break;
    }
  });
}
/*
Catch: 为当前对象只绑定失败的回调函数,返回一个新的成功 promise 对象,并且新的 promise 对象的 data 是 undefined
Onrejected: 失败的回调
*/
Promise. Prototype. Catch = function (onrejected) {
  Return this.Then (undefined, onrejected);  //直接调用该对象的 then 方法,将成功的回调设置成非函数值,在 then 方法中会转化成向下传递值的回调函数,就会返回一个新的且 data 值是 undefined 的 promise 对象
}
/*
Resolve: 返回一个状态是成功且指定 data 为 value 的 promise 对象
Value: 可以是一个 promise 对象,可以是一个普通值
*/
Promise. Resolve = function (value) {
  If (value instanceof Promise) { //若是一个 promise 对象
    Return value; //则直接返回该 promise 对象
  } else {  //若是普通值
    Return new Promise ((resolve, reject) => {  //将值包装成成功的 promise 对象并返回
      Resolve (value);
    })
  }
}
/*
Reject: 返回一个状态为失败的 promise 对象
Reason: 失败原因
*/
Promise. Reject = function (reason) {
  Return new Promise ((resolve, reject) => {
    Reject (reason);
  });
}
/*
All: 返回一个 promise,只有当所有 promise 对象成功时才成功,否则失败
*/
Promise. All = function (promises) {
  Const values = new Array (promises. Length);  //创建一个与 promises 对应的数组,用来存放每个 promise 对象的返回值
  Let count = 0;  //成功的 promise 计数器
  Return new Promise ((resolve, reject) => {
    For (let i = 0; i < promises. Length; i++) { //遍历 promises 数组
      Promise.Resolve (promises[i]). Then (  //数组元素若是普通值使用 Promise. Resolve 进行包装为成功的 promise 对象
        Value => {
          Count++;  //每成功一个该计数器加一
          Values[i] = value;  //将执行成功回调函数的 value 添加到 values 对应位置
          If (count === promises. Length) {
            Resolve (values);  //当所有都成功时,则返回的就是失败的 promise 对象,并且 data 值是 values 数组
          }
        },
        Reason => {  //只要有一个执行了失败的回调,则返回的就是失败的 promise 对象
          Reject (reason)
        }
      )
    }
  });
}
/*
Race: 返回一个 promise,第一个完成的 promise 是成功的该返回的就是成功的 promise,第一个完成的 promise 是失败的该返回的就是失败的 promise
*/
Promise. Race = function (promises) {
  Return new Promise ((resolve, reject) => {
    For (let i = 0; i < promises. Length; i++) { //遍历 promises 数组
      Promise.Resolve (promises[i]). Then (resolve, reject); //数组元素若是普通值使用 Promise. Resolve 进行包装为成功的 promise 对象
    }
  })
}

Generator 函数与异步

生成器函数可以依靠 yield 表达式暂停函数执行,若在异步回调函数中调用生成器函数返回的迭代器的 next 方法,就可以保证这些异步操作串行执行

Function* async () {
    Let t = yield setTimeout (() => {
        Console.Log (1);
        It.Next ("yield 表达式的返回值");  //异步回调中调用当前生成器函数返回的迭代器的 next 方法
        //甚至还可以使用带参的 next 方法指定 yield 表达式的值,来影响下一个异步任务
    }, 2000);
    Yield setTimeout (() => {    //等到上个异步任务执行时才会启动该当前异步任务
        Console.Log (t); //输出上一个异步任务指定的 yield 的表达式的值
    }, 1000);
}
Let it = async ();   //获取迭代器,该迭代器会在这个生成器函数中使用到
It.Next ();  //开始执行生成器函数

若所有异步任务都使用 promise 对象进行封装,使用迭代器的 next 方法获取的对象其中 value 值就是指定的 promise 对象,promise 对象可以绑定多个成功或失败的回调,再为这些 promise 对象绑定一个调用该迭代器 next 的回调,就可以保证多个异步任务串行执行

Function autoRun (gen) {
    Const g = gen ();    //获取迭代器
    Function next (data) {
        const result = g.next (data);	//向下执行生成器函数,并替换 yield 表达式的值,从而影响下一个异步任务
        If (result. Done === false) {    //若迭代器未结束
            Promise.Resolve (result. Value)   //若 yield 后不是 promise 对象则将他转化为成功的 promise 对象
                .then (value => next (value)) //则为当前 promise 对象绑定执行迭代器 next 方法的函数
        }
    }
    Next ();
}

AutoRun (function* () {
    Let a = yield new Promise ((resolve, reject) => {
        SetTimeout (() => {
            Console.Log (1);
            Resolve (2);
        }, 1000)
    });
    A = yield new Promise ((resolve, reject) => {
        SetTimeout (() => {
            Console.Log (a);
            Resolve (3);
        }, 1000)
    });
    A = yield new Promise ((resolve, reject) => {
        SetTimeout (() => {
            Console.Log (a);
            Resolve (1);
        }, 1000)
    });
});

Async 函数

声明

  • 于普通的函数类似,只不过使用async修饰的方法,但是不能作为构造函数那样使用
  • 使用return语句返回的必然是一个 promise 对象
    • 返回一个普通值=成功的包装该值的 promise 对象
    • 返回一个 promise 对象=该 promise 对象
    • 抛出错误=返回一个包装该错误的 promise 对象
Async function afun (){
    // return 1;   //Promise {<resolved>: 1}
    // throw 1;    //Promise {<rejected>: 1}
  
    // return new Promise ((resolve, reject)=>{
    //     // resolve (1);  //Promise {<resolved>: 1}
    //     // reject (1);    //Promise {<rejected>: 1}
    //     //throw 1;    //Promise {<rejected>: 1}
    // })
}
Console.Log (afun ());



Await 表达式

  • 只能在 async 函数中使用
  • Await 后跟一个表达式
    • 该表达式是一个 promise 对象,则该表达式的值是该 promise 对象成功的返回结果,如果该 promise 对象失败了就会抛出错误,需要用try... Catch捕获错误才能得到该 promise 对象失败的返回结果
    • 该表达式是一个普通表达式,则该表达式的值是这个普通表达式的值,即有没有 await 声明是一样的
(async function () {
    Const t = await Promise.Resolve (1);
    Console.Log (t); //1
})();
//失败的 promise
(async function () {
    Try {
        Const t = await Promise.Reject (1);
        Console.Log (t); //抛出错误,所以这里不会执行到
    } catch (err) {
        Console.Log (err); //1
    }
})();
//普通表达式
(async function () {
    Const t = await 1 + 1;
    //等价于
    // const t = 1 + 1;
    Console.Log (t); //2
})();

Async 函数执行流程

  • 调用该函数则该函数同步执行,只有遇到await表达式并且右部是 promise 对象才会进入异步执行状态
Async function afun (){
    Console.Log (1);
}
Afun ();
Console.Log (2);
// 1
// 2


Async function afun (){
    Await Promise.Resolve ();
    Console.Log (1);
}
Afun ();
Console.Log (2);
// 2
// 1

Async 实现原理

其实就是生成器函数自动串行执行的升级版,多绑定了一个失败的 promise 对象的回调函数

Function autoRun (gen) {
    Return new Promise ((resolve, reject) => {   //异步函数一定返回的是 promise 对象
        Const g = gen ();    //获取迭代器对象
        Function next (data, status = 1) {   //status 状态是 1 说明是成功的 promise,其他值则是失败的 promise
            Let result; //保存迭代器结果对象
            Try {
                result = status === 1 ? g.next (data) : g.throw (data);   //根据 status 决定将 yield 表达式替换为什么
                //向下执行生成器函数,并替换 yield 表达式的值,从而影响下一个异步任务
            } catch (e) {   //若生成器函数中抛出错误
                Reject (e);  //则将错误捕获后,并将返回的 promise 对象变为失败的状态,reason 是捕获的错误信息
            }
            If (result. Done === false) {    //若迭代器未结束
                Promise.Resolve (result. Value)   //若 yield 后不是 promise 对象则将他转化为成功的 promise 对象
                    .then (
                        (value) => next (value), //则为当前 promise 对象绑定成功的回调函数,其中中要执行迭代器 next 方法的函数
                        (error) => next (error, 0)  //则为当前 promise 对象绑定失败的回调函数,其中中要执行迭代器 throw 方法的函数
                    );
            } else {    //若迭代器结束
                Resolve (result. Value);  //返回成功的 promise 对象,并且值是最后一个 return 语句后的值
            }
        }
        Next ();
    });
}
加油啊!即便没有转生到异世界,也要拿出真本事!!!\(`Δ’)/
最后更新于 2023-03-17