promise

1. 必备知识点

1. 函数对象&实例对象

将函数作为对象使用(调用函数的属性和方法),简称函数对象
【括号左边是函数,点的左边是函数对象】

new 函数产生的对象,称为实例对象,简称对象。

2. 链式调用

想要不断的调用(链式调用),需要返回自己,或者返回一个和自己类似的结构。

//方式一:返回自己
class Test1{
  then(){
    console.log(6666);
    return this;
  }
}

var a= new Test1();
a.then().then().then()

//方式二:一个和自己类似的结构
//promise采用这种方式,因为一个promise只能改变一次状态,要么从pending转化为fulfilled,要么从pending转化为rejected.
class Test2{
  then(){
    console.log(77777);
    return new Test2();
  }
}

var b= new Test2();
b.then().then().then()

3. 回调函数的分类

回调函数的分类

<script>
	//1.同步回调函数
	const arr = [1,2,3,5];
	//forEach()中的回调函数为同步回调函数
	arr.forEach(item =>{
		console.log(item);
	})
	console.log("forEach()之后");
	/*
	 * 执行结果:
	 * 1
	 * 2
	 * 3
	 * 4
	 * forEach()之后
	 */
	
	//2.异步回调函数
	//setTimeout()中的回调函数为异步回调函数
	setTimeout(()=>{
		console.log("timout callback()");
	},0);
	console.log("setTimeout()之后");
	/*
	 * 执行结果
	 * setTimeout()之后
	 * timout callback()
	 */
</script>

4. 错误和错误处理

相关概念

<script>
	//抛出异常:throw error
	function something(){
		if(Date.now()%2 ===1){
			console.log("当前时间为奇数,可以执行任务");
		}else{
			throw new Error("当前时间为偶数,无法执行任务");
		}
	}
	//捕获异常处理
	try{
		something();
	}catch(error){
		alert(error.message);
	}
</script>

2. promise是什么?

promise是es6中用来解决异步编程的一种方式。通过链式调用的方式, 可以解决回调地狱问题。项目中常用的axios就是把ajax使用promise封装了一下。

3.promiseA+规范及应⽤

promiseA+规范以及应⽤

4. 为什么使用promise?

promise支持链式调用, 可以解决回调地狱问题

  • 什么是回调地狱?
    回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调函数执行的条件
  • 回调地狱的缺点?
    不便于阅读 / 不便于异常处理
    解决方案? promise链式调用
    终极解决方案? async/await
    //1、查出当前用户信息
    //2、按照当前用户的id查出他的课程
    //3、按照当前课程id查出分数
    // 回调地狱:
    $.ajax({
        url: "./mock/user.json",
        success(data) {
            console.log("查询用户:", data);
            $.ajax({
                url: `./mock/user_corse_${data.id}.json`,
                success(data) {
                    console.log("查询到课程:", data);
                    $.ajax({
                        url: `./mock/corse_score_${data.id}.json`,
                        success(data) {
                            console.log("查询到分数:", data);
                        },
                        error(error) {
                            console.log("出现异常了:" + error);
                        }
                    });
                },
                error(error) {
                    console.log("出现异常了:" + error);
                }
            });
        },
        error(error) {
            console.log("出现异常了:" + error);
        }
    });
    
    // promise调用方式
    function get(url, data) {
        return new Promise((resolve, reject) => {
            $.ajax({
                url: url,
                data: data,
                success: function (data) {
                    resolve(data);
                },
                error: function (err) {
                    reject(err)
                }
            })
        });
    }
    
    //调用封装后的方法
    get("./mock/user.json")
        .then((data) => {
            console.log("用户查询成功~~~:", data)
            return get(`./mock/user_corse_${data.id}.json`);
        })
        .then((data) => {
            console.log("课程查询成功~~~:", data)
            return get(`./mock/corse_score_${data.id}.json`);
        })
        .then((data) => {
            console.log("课程成绩查询成功~~~:", data)
        })
        .catch((err) => {
            console.log("出现异常", err)
        });
    // Promise操作明显更加符合我们人类的习惯,类似于流水线式的操作,对于异常的处理更加友好
    // 测试代码在promise-test.html中
    

promise面试题

  • 使用Promise实现红绿灯交替重复亮【面试真题】

    /*
    红灯3秒亮一次,黄灯2秒亮一次,绿灯1秒亮一次;如何让三个灯不断交替重复亮灯?(用Promise实现)
    */
    function red() {
      console.log("red");
    }
    function green() {
      console.log("green");
    }
    function yellow() {
      console.log("yellow");
    }
    function light(cb, timer) {
      return new Promise(resolve => {
          setTimeout(() => {
              cb();
              resolve()
          }, timer);
      })
    }
    
    function step() {
      Promise.resolve().then(() => {
          return light(red, 3000)
      }).then(() => {
          return light(green, 2000)
      }).then(() => {
          return light(yellow, 1000)
      }).finally(() => {
      	  // 递归实现循环
          return step()
      })
    }
    step();
    
  • promise实现sleep函数【面试题】

    	//Promise实现Sleep函数
    	function sleep(ms) {
    	  return new Promise(resolve => setTimeout(resolve, ms));
    	}
    	async function test() {
    	  console.log(new Date());
    	  await sleep(3000);
    	  console.log(new Date());
    	}
    	test();
    
  • 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个

    // JS 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个
    class Scheduler {
      constructor(limit) {
        this.limit = limit
        this.queue = []
        this.count = 0
      }
      add(time, str) {
        const doTask = () => {
          return new Promise(resolve => {
            setTimeout(() => {
              console.log(str)
              resolve()
            }, time)
          })
        }
        this.queue.push(doTask)
      }
      taskStart() {
        for(let i = 0; i < this.limit; i++) {
          this.request()
        }
      }
    
      request() {
        if (!this.queue.length || this.count > this.limit) {
          return
        }
        this.count++
        this.queue.shift()().then(() => {
          this.count--
          this.request()
        })
      }
    }
    let kk = new Scheduler(2)
    
    kk.add(1000,"1");
    kk.add(500,"2");
    kk.add(300,"3");
    kk.add(400,"4");
    
    kk.taskStart()
    // 2 3 1 4
    
  • 将图片的加载写成一个Promise,一旦加载完成,Promise的状态就发生变化

    const preloadImage = function (path) {
      return new Promise(function (resolve, reject) {
        const image = new Image();
        image.onload  = resolve;
        image.onerror = reject;
        image.src = path;
      });
    };
    
  • promise相关面试题

5. async function 与 await expression

阮一峰老师文档

  1. async function 函数名() { // 。。。}
    调用async 函数返回结果是一个Promise对象,promise对象的结果由async函数执行的返回值决定

    // async函数返回一个promise对象
    async function fn1() {
      return 1
      //throw 2
      //return Promise.resolve(3)
      /*return new Promise((resolve, reject)=>{
        setTimeout(()=>{
          resolve(4)
        }, 1000)
      })*/
    }
    //调用async函数
    const result = fn1()
    
    result.then(
      value => {
        console.log('onFulfilled()', value)
      },
      reason => {
        console.log('onRejected()', reason)
      }
    )
    
  2. await expression (value or Promise)
    expression一般是Promise对象,也可以是其他值
    如果是Promise对象,await返回的是Promise对象成功的值, 如果await的Promise失败,就会抛出异常,需通过try…catch…捕获处理
    如果是其他值,直接将此值作为await的返回值

    <script>
    	function fn2(){
    	  return new Promise((resolve, reject)=>{
    	    //resolve(4)
    	     reject(6)
    	  })
    	}
    	
    	async function fn3(){
    	  try{
    	  // await右侧表达式为Promise,得到的结果就是promise成功的value,
    	    const value = await fn2()
    	    console.log('fn5 value', value) // fn5 value 4
    	  }catch(error){
    	  //如果await右侧的Promise失败,就会直接抛出异常,需通过catch捕获处理进行处理
    	    console.log('fn5 error', error) // fn5 error 6
    	  }
    	}
    	
    	fn3()
    	
    	function fn4(){
    	  return 5
    	}
    	
    	async function fn5(){
    	  //await右侧表达式不为Promise,得到的结果就是它本身
    	  const value = await fn4() 
    	  console.log('value', value)// value 5
    	}
    	
    	fn5()
    </script>
    
  3. await expression必须写在async function 中,但async function可以没有await expression

  4. async函数可以理解为内置自动执行器的Generator函数语法糖,它配合Promise近乎完美的实现了异步编程解决方案

    async function async1(){
    	console.log('async1 start...');
    	await async2();
    	//await后面的代码,都可以看作是放在一个回调函数里的代码,是异步的,放在微任务队列中
    	console.log('async1 end...')
    }
    
    async function async2(){
    	console.log('async2');
    }
    
    console.log('start');
    async1();
    console.log('end');
    /*
     * 执行结果:
     * start
     * async1 start...
     * async2
     * end
     * async1 end...
     */
    

6. 宏队列与微队列

  1. 为什么要引入微任务的方式来进行回调操作,只有宏任务不行吗?
    任务队列里的任务遵循先进先出的原则,若当前队列非常长,一些优先级比较高的回调放在进行宏任务队列的队尾,那么该回调迟迟得不到执行,造成的效果就是应用卡顿。所以就引入了微任务,来存放优先级更高的任务。

  2. 在这里插入图片描述

  3. js执行顺序:

    1. 渲染DOM
    2. 执行宏队列的宏任务
    3. 执行本周期中的微任务
    4. 循环以上三步
    //例1:
    <script>
    	setTimeout(()=>{  //立即放入宏队列
    	   console.log('timeout callback1()')
    	   Promise.resolve(3).then(
    	     value => {  //立即放入微队列
    	       console.log('Promise onResolved3()', value)
    	     }
    	   )
    	 },0)
    	
    	 setTimeout(()=>{  //立即放入宏队列
    	   console.log('timeout callback2()')
    	 },0)
    	
    	 Promise.resolve(1).then(
    	   value => {  //立即放入微队列
    	     console.log('Promise onResolved1()', value)
    	     setTimeout(()=>{
    	       console.log('timeout callback3()', value)
    	     },0)
    	   }
    	 )
    	
    	 Promise.resolve(2).then(
    	   value => {  //立即放入微队列
    	     console.log('Promise onResolved2()', value)
    	   }
    	 )
    	 /*
    	  * 执行结果
    	  * Promise onResolved1() 1
    	  * Promise onResolved2() 2
    	  * timeout callback1()
    	  * Promise onResolved3() 3
    	  * timeout callback2()
    	  * timeout callback3() 1
    	  */
    </script>
    
    //例2:
    <script>
    	Promise.resolve()
    	  .then(() => {
    	    console.log("then1");
    	    Promise.resolve()
    	      .then(() => {
    	        console.log("then1-1");
    	        return 1;
    	      })
    	      .then(() => {
    	        console.log("then1-2");
    	      });
    	  })
    	  .then(() => {
    	    console.log("then2");
    	  })
    	  .then(() => {
    	    console.log("then3");
    	  })
    	  /*执行结果:
    	   * then1
    	   * then1-1
    	   * then2
    	   * then1-2
    	   * then3
    	   */
    	   /*
    	   第一次 resolve 后第一个 then 的回调进入微任务队列并执行,打印 then1
    	   第二次 resolve 后内部第一个 then 的回调进入微任务队列,此时外部第一个 then 的回调全部执行完毕,需要将外部的第二个 then 回调也插入微任务队列。
    	   执行微任务,打印 then1-1 和 then2,然后分别再将之后 then 中的回调插入微任务队列
    	   执行微任务,打印 then1-2 和 then3 
    	   */
    </script>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值