异步编程-promise

145 阅读6分钟

异步编程

常见的异步编程方式有 回调函数,事件发布/订阅,Promise,generator函数,async函数
这篇笔记是记录一下学习promise的过程,回调和事件发布/订阅,就不记录笔记了

promise

Promise/A+规范

1 术语

promise :一个有then方法的对象或者函数,行为符合本规范

thenable :一个对象或者函数,拥有then方法

值,value :任何javascript 的合法值

异常,exception :throw语句抛出的值

拒绝原因,reason :一个标示promise被拒绝原因的值

术语的含义下文会慢慢分析

2 要求

promise状态

pending

等待状态,可以转换为fulfilled状态或者rejected状态 fulfilled 完成状态,不可以转换成其他的状态,且必须带有value,且这个值不能被改变 rejected 拒绝状态,不可以转换成其他的状态,且必须带有reason,且这个值不能被改变

then方法

then方法的参数

一个promise必须提供then方法一个参数才能获取其value或者reason

then方法接受两个参数,promise.then(onFulfilled,onRejected)

onFulfilled在promise完成之后调用,onRejected在promise被拒绝之后调用,并且只能调用一次 ,因为上文状态说明只能状态一旦改变,就无法再次改变,所以意味着两种方法只能调用一次

then方法的调用

then方法可以被同一个promise调用多次,onFulfilled和onReject会按照注册的顺序依次调用

then方法的返回值

then方法必须返回一个promise let promise2=promise1.then(onFulfilled, onRejected)

promise2的值和状态

onFulfilled不是函数则忽略之

onRejected不是函数则忽略之

onRejected或者onFulfilled return了一个值X,则进入解析过程,promise解析过程 可以提取一个抽象模型resolve(promise,x) x是then的参数返回的值,

1 如果promise和x指向同一个值
2 如果x是一个promise
3 如果x是一个对象或者函数
4 如果x不是对象也不是函数
下面结合代码分析解析过程

          function resolve(promise, x) {
           //如果promise和x指向同一个值,则以typeError为因,拒绝执行promise
            if (x === promise) {
              return reject(promise, new TypeError("cant be the same"));
            }
            //如果x是一个promise
            if (isPromise(x)) {
             //如果x.state为fulfilled,则将x.value 作为promise的value,并且将promise设为fulfilled状态
              if (x.state === "fulfilled") {
                return fulfill(promise, x.value);
              }
             //x.state是rejected ,则将x.reason作为promise的值,并且将promise设为rejected状态
              if (x.state === "rejected") {
                return reject(promise, x.reason);
              }
              //如果x.state是pending 状态,则需要等待state变化之后,才能决定promise的state和value
              //所以需要将promise状态的改变放到then方法的回调里面
              if (x.state === "pending") {
                return x.then(
                  () => {
                    //如果是fulfilled,则再走一遍解析
                    resolve(promise, x.value);
                  },
                  () => {
                   //如果是rejected,则将x.reason作为promise的值,并且将promise设为rejected状态
                    reject(promise, x.reason);
                  }
                );
              }
            } else if (isObject(x) || isFunction(x)) {
             //x是一个对象或者函数(thenable)
             //为什么术语中会出现一个和promise如此相似的thenable呢?因为在规范出现之前,已经有库实现了类似promise的功能,
             //所以为了对这些库兼容,就针对thenable在规范中进行了一个处理
             //直接去取x.then
              let then;
              let isCalled = false;
              //如果出现异常,则将抛出的异常作为reason,将promise设置为rejected状态
              try {
                then = x.value;
              } catch (e) {
                return reject(promise, e);
              }
              //如果是一个函数
              if (isFunction(then)) {
                try {
                 //以x为this调用then函数
                 //将两个函数作为onFulfilled和onRejected参数传给then
                 //then方法在执行的时候,更具不同的情况调用函数
                 //根据上文可知,要保证函数只被调用一次,因为我们希望thenable是类似promise的
                  then.call(
                    x,
                    function resolvePromise(y) {
                      if (isCalled) return;
                      isCalled = true;
                      resolve(promise, y);
                    },
                    function rejectPrommise(r) {
                      if (isCalled) return;
                      isCalled = true;
                      reject(promise, r);
                    }
                  );
                } catch (e) {
                  //如果执行过程出错,则需要看一下两个函数是否已经执行过了
                  //如果执行过了,则说明promise状态已经被改变了,所以不做处理
                  //如果没有执行过,则将执行时的异常作为reason,将promise设置为rejected状态
                  if (!isCalled) return reject(promise, e);
                }
              } else {
                //如果then不是function ,则需要将x作为promise一个值,将promise设置为fulfilled状态
                return fulfill(promise, x);
              }
            } else {
              //如果x不是对象也不是函数,则将x作为promise一个值,将promise设置为fulfilled状态
              return fulfill(promise, x);
            }
          }
根据规范看一下代码示例
          const promise = new Promise((resolve, reject) => {
            console.log(1);
            resolve();
            console.log(2);
          });
          promise.then(() => {
            console.log(3);
          });
          console.log(4);
          // 这个很简单 1 2 4 3 
          const promise = Promise.resolve(1)
            .then(2)
            .then(Promise.resolve(3))
            .then(console.log); 
            // 这段代码如果刚开始看不懂的话,可以分解一下
          const promise1 = Promise.resolve(1); //通过resolve方法将promise1变为fulfilled状态,value为1
          const promise2 = promise1.then(2); //onFulfilled不是函数且promise1的state是fulfilled 则promise2的state:fulfilled value:同promise1
          const promise3 = promise2.then(Promise.resolve(3)); //同上
          const promise4 = promise3.then(console.log); //因为console.log是一个function,其参数为promise3的value

ES6 Promise API

没啥好说的,就简单记录一下

new Promise((resolve,reject)=>{
// resolve() //将promise从pending状态变成 fulfilled
// reject() //将promise从pending状态变成 rejected
})

Promise.resolve(param) 等同于 new Promise((resolve,reject)=>resolve(param))

Promise.reject(reason) 等同于 new Promise((resolve,reject)=>reject(reason))

Promise.all([p1,...,pn]) 输入一组promise返回一个新的promise ,全部promise的状态为fulfilled结果才是fulfilled状态,否则就是rejected状态

Promise.race([p1,...,pn]) 输入一组promise返回一个新的promise,只要有一个promise被fulfilled,结果promise就会状态就会变成fulfilled

Promise.allSettled([p1,...,pn]) 输入一组promise返回一个新的promise,全部promise的状态改变之后结果promise才会使fulfilled状态

promise实例方法

promise.then(onFulfilled,onRejected) promise状态改变之后的回调,返回新的promise对象

promise.catch((reason)=>{}) 等同于promise.then(null,onRejected)

promise.finally((reason)=>{}) 不管promise状态如何都会执行

promise 实践

3S之后亮红灯一次,再过两秒亮绿灯一次,再过一秒亮黄灯一次 ,用promise实现多次交替亮灯的效果

拆解步骤 1多少秒后亮那一盏灯 2顺序亮灯 3循环顺序亮灯

        let lightList = [{
            color: "red",
            second: 3,
        }, {
            color: "green",
            second: 2,
        }, {
            color: "yellow",
            second: 1,
        }, ];
        //对list进行某种操作
        function loopLight(list) {
            let promise = Promise.resolve();
            list.forEach((item) => {
                promise = promise.then(() => {
                    return lightUp(item.color, item.second);
                });
            });
        }
        //亮灯
        function lightUp(color, second) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(color);
                    resolve();
                }, second * 1000);
            });
        }
        loopLight(lightList);

上面的代码可以实现第一步和第二步,如果想实现循环亮灯需要对loopLight进行修改,只要在forEach完成之后,再次运行,下面写上完整代码

        let lightList = [{            color: "red",            second: 3,        }, {            color: "green",            second: 2,        }, {            color: "yellow",            second: 1,        }, ];

        function lightUp(color, second) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(color);
                    resolve();
                }, second * 1000);
            });
        }

        function loopLight(list) {
               //then方法必须返回一个返回值:Promise
               //then 方法可以被同一个Promise 方法调用多次,那么onFulfilled, onRejected会按照注册顺序调用
            let promise = Promise.resolve();
            list.forEach((item) => {
                promise = promise.then(() => {
                    return lightUp(item.color, item.second);
                });
            });
            promise.then(() => {
                loopLight(lightList);
            });
        }
        loopLight(lightList);

这篇笔记到此结束,如果有错误或者更好的方法,希望看到的大佬不吝赐教。