javascript中的运行机制(EventLoop)、promise、await、ayncs

(一):EventLoop、js的运行机制

因为javascript语言特点就是单线程,这就意味着所有的任务都需要排队,只有当前一个任务结束后,才会执行后一个任务,如果前一个任务耗时很长,那有一个任务就得一直等着,于是js的所有任务又分为同步任务异步任务,同步任务是指:在主线程上排队执行的任务,从上往下执行。异步任务是指:所有的异步任务不会进入主线程,而是会进入任务队列(task queue),只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行;

  • 异步执行的运行机制如下
    1、所有的同步任务都在主线程执行,形成一个执行栈(execution content stack)。
    2、所有的异步任务都在任务队列(task queue)中,只有异步任务有了运行结果,就在 任务队列中放置一个事件,通知主线程可以执行该任务了(任务队列中的事件:除了IO设备的事件以外,还包括用户产生的事件,比如鼠标点击、页面滚动等等)。
    3、当执行栈中的同步任务执行完毕后,就会读取 任务队列 中的事件,然后这些 异步任务 进入执行栈中开始执行。
    4、主线程会不断读取 任务列表 中的事件,
    只要主线程空了,就会读取 任务队列 ,这就是javascript的运行机制,因为这个过程是循环不断的,所以整个的这种运行机制又称为EventLoop(事件循环)

(二):Promise异步处理

promise主要用于异步任务的操作,解决了代码嵌套的问题,promise中的代码会立即执行;
promise的又三种状态:

  1. pending (进行中)
  2. fulfilled(已成功)
  3. rejected(已失败)
    这三种状态只能从pending到fulfilled,或者pending到rejected两种情况,状态的改变是不可逆的,下面看一下这段代码的执行顺序
	console.log(1); // 同步
    new Promise((resolve, reject) => {
      console.log(2); // 这里的代码会立即执行
      setTimeout(() => { 
        console.log(3); // 第一个异步任务
      }, 0);
    }).then(() => {
       console.log(4); // 这里的代码只有当状态改变为fufilled的时候才会执行
    }).catch(err => {
		// 当状态改变为rejected的时候才会执行
	})
    setTimeout(() => { 
      console.log(5); // 第二个异步任务
    }, 0);
    console.log(6); // 同步
	// 1、2、6、3、5

然后在看下一段代码

	new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log(3); // 第一个异步任务
        resolve() // 改变promise的状态, 从pending --> fulfilled 
      }, 0);
    }).then(() => {
      console.log(4); // 挡状态改变的时候就会立即执行
    });
    setTimeout(() => {
      console.log(5); 
    }, 0);
	// 3、4、5

在来一段

	new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log(3);
      }, 0);
      resolve()
    }).then(() => {
      console.log(4);
    });
    setTimeout(() => {
      console.log(5);
    }, 0);
    // 4、3、5

下面这段代码,有点绕

	new Promise((resolve, reject) => {
      console.log(0)
      setTimeout(() => {
        console.log(4);
      }, 0);
      resolve()
      
    }).then(() => {
      console.log(1)
    }).then(() => {
      setTimeout(() => {
        console.log(5)
      }, 0)
    })
    console.log(3)
    setTimeout(() => {
      console.log(6);
    }, 0);
    // 0、3、1、4、6、5

promise的缺点
1、创建promise后会立即执行,不能中途取消;
2、如果不设置回调函数,promise内部抛出的错误,外部无法知晓
3、当处于pending状态的时候,无法得知进展到那个阶段
promise实现的简单原理

// 第一步:Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
// 它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
    function Promise(task) {

        let that = this; // 缓存this
        that.status = 'pending'; // 进行中的状态
        that.value = undefined; //初始值

        that.onResolvedCallbacks = []; // 存放成功后要执行的回调函数的序列
        that.RejectedCallbacks = []; // 存放失败后要执行的回调函数的序列
        // 该方法是将Promise由pending变成fulfilled
        function resolve (value) {
            if (that.status == 'pending') {
                that.status = 'fulfilled';
                that.value = value;
                that.onResolvedCallbacks.forEach(cb => cd(that.value))
            }

        }
        // 该方法是将Promise由pending变成rejected
        function reject (reason) {
          if (that.status == 'pending') {
                that.status = 'rejected';
                that.value = reason;
                that.onRjectedCallbacks.forEach(cb => cd(that.value))
            }
        }

        try {
        // 每一个Promise在new一个实例的时候 接受的函数都是立即执行的
            task(resolve, reject)
        } catch (e) {
            reject(e)
        }
    }

// 第二步 写then方法,接收两个函数onFulfilled onRejected,
// 状态是成功态的时候调用onFulfilled 传入成功后的值,
// 失败态的时候执行onRejected,传入失败的原因,
// pending 状态时将成功和失败后的这两个方法缓存到对应的数组中,当成功或失败后 依次再执行调用
    Promise.prototype.then = function(onFulfilled, onRejected) {
        let that = this;
        if (that.status == 'fulfilled') {
            onFulfilled(that.value);
        }
        if (that.status == 'rejected') {
            onRejected(that.value);
        }
        if (that.status == 'pending') {
            that.onResolvedCallbacks.push(onFulfilled);
            that.onRjectedCallbacks.push(onRejected);
        }
    }

(三) async await异步处理

async 函数在function 前面加一个async作为标识,表示为异步函数,在函数体内部需要搭配await来使用

async函数的特点:
1、处理异步函数的语义化强
2、await只能在async中使用
3、async标识的函数返回的是一个Promise对象
4、await语句后面的Promise对象变成rejected状态的时候,那么async函数会中断,后面的程序不会执行

直接上代码:

	function f1() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('你好') 
        }, 10)
      })
    }
    async function createAsync(){
      await f1();
      console.log('222')
    }
    createAsync()

这段代码只会打印出 你好,222不会被打印出来,因为f1函数返回的promise的状态没有被改变,所以createAsync函数会被中断

	function f1() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('你好') 
          resolve() // 改变promise的状态为fulfilled
        }, 10)
      })
    }
    async function createAsync(){
      await f1();
      console.log('222')
    }
    createAsync()
    // 此时打印 你好  222

这里可以看出 await 后面的函数需要返回一个promise对象,并且要改变promise对象的状态才能执行f1函数后面的内容
参数的传递:

	function f1() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('你好') 
          resolve('传参')
        }, 10)
      })
    }
    async function createAsync(){
      const param = await f1();
      console.log(param)
    }
    createAsync()

错误捕获,当f1函数中的promise的状态改为rejected的时候,处理方式:

	function f1() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('你好') 
          reject('错误处理, promise的状态修改为rejected')
        }, 10)
      })
    }
    async function createAsync(){
      try {
        const param = await f1();
        console.log(param)
      } catch(e) {
        console.log(e)
      } finally {
        console.log('5555')
      }
    }
    createAsync()

async函数需要通过try{} catch(e){}的语法来捕获错误
try语法介绍:
1、try语句允许我们定义在执行时进行错误测试的代码块。
2、catch 语句允许我们定义当 try 代码块发生错误时,所执行的代码块。
3、finally 语句在 try 和 catch 之后无论有无异常都会执行。
注意: catch 和 finally 语句都是可选的,但你在使用 try 语句时必须至少使用一个。

欢迎大家评论,如果觉得有用,可以点个赞,感谢大家哈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值