ES6-18【异步的开端-promise】

一、异步的开端

  1. JS执行机制

    JS是单线程的语言,所以会有代码阻塞,要想避免代码阻塞就得通过异步,而异步的实现原理就是通过事件环,它会把异步任务寄托到浏览器,浏览器将异步任务处理完后会将其推送到任务队列,等JS主线程执行完毕后,会一个一个执行任务队列里的异步任务。

  2. 异步存在的问题

    1. 回调地狱 —— 难于维护,不便拓展

      呈现倒三角的写法就是回调地狱

      let fs = require('fs');
      fs.readFile('./name.txt','utf-8',(err,data)=>{
      	console.log(data); 				// ./number.txt
          if(data){
              fs.readFile(data,'utf-8',(err,data)=>{
                  console.log(data); 		// score.txt
                  fs.readFile(data,'utf-8',(err,data)=>{
                      console.log(data);  // 90
                  })
              })
          }
      })
      
    2. try-catch —— 难以捕获异常

      只能捕获同步异常,无法捕获异步错误

      直接报错

      try {
          setTimeout(()=>{
              console.log(a); // Uncaught ReferenceError: a is not defined
          },90)
      } catch (e) {
          console.log(e); 
      }
      

      捕获不到

      let fs = require('fs');
      try {
          fs.readFile('./nam.txt', 'utf-8', (err, data) => {
              if (err) {
                  console.log(err);
                  // [Error: ENOENT: no such file or directory, open 'C:\Users\21757\Desktop\ES6\nam.txt'] {
      			//     errno: -4058,
      			//     code: 'ENOENT',
      			//     syscall: 'open',
      			//     path: 'C:\\Users\\21757\\Desktop\\ES6\\nam.txt'
      			//   }
              }
          });
      } catch (e) {
          console.log(e);
      }
      
    3. 同步并发异步任务 —— 没法判断谁先执行

      每一个异步函数中都要加入 arr.length === 3 && show(arr) 判断是否读取完

      let fs = require('fs');   
      let arr = []
      function show(data){
          console.log(data);
      }
      fs.readFile('./name.txt','utf-8',(err,data)=>{
          if(data){
              arr.push(data)
          }
          arr.length === 3 && show(arr);
      })
      fs.readFile('./number.txt','utf-8',(err,data)=>{
          if(data){
              arr.push(data)
          }
          arr.length === 3 && show(arr);
      })
      fs.readFile('./score.txt','utf-8',(err,data)=>{
          if(data){
              arr.push(data)
          }
          arr.length === 3 && show(arr);
      })
      // ['./number.txt','scores.txt','90']
      
  3. promise演变历史

    1. Callbacks() —— 管理回调列表(已过时)

      在jquery中可以通过 add 方法将异步任务推到 Callbacks 里面进行管理

      // 引入JQuery
      let cb = $.Callbacks();
      function a(x,y){
          console.log('a',x,y)
      }
      function b(x,y){
          console.log('b',x,y)
      }
      cb.add(a,b); //添加异步方法
      cb.fire(10,20); //执行所有异步
      //a 10 20
      //b 10 20
      
    2. deferred(即将淘汰)

      底层是通过 Callbacks 管理当前的回调,实现异步的管理

      缺点:可以显示调用 reject,于是采用 promise 来解决,这就是 promise 的由来

      function waitHandle(){
          var dtd = $.Deferred(); //创建一个 deferred 对象;
          var wait = function(dtd){ //传入一个 deferred 的对象
              var task = function(){ 
                  console.log('执行完成');
                  dtd.resolve(); //表示异步任务已经完成
                  // dtd.reject(); //表示异步任务失败或出错;打印失败的回调
              }
              setTimeout(task,2000);
              // return dtd; //里层函数,返回 deferred 对象
              return dtd.promise(); //注意,这里返回的是 promise 而不是直接返回 deferred
          }
          // 外层函数返回 里层函数的执行结果
          return wait(dtd)
      }
      var w = waitHandle();
      console.log(w);
      
      //w.done(function(){
      //	console.log('ok');
      //}).fail(function(){
      //	console.log('err');
      //}); // 执行完成  ok
      
      // w.reject(); // deferred弊端:deferred 对象可以显示调用 reject 方法,而 promise 对象无法调用 
      w.then(function(){
      	console.log('ok');
      }).fail(function(){
      	console.log('err');
      }); // 执行完成  ok
      
    3. promise A+规范

      本身是社区的一个规范,用于定义 promise 的用法,最后被囊括在了es6

二、promise

  1. promise初识

    是一种异步操作,js内置的构造函数

    参数是一个函数(executor 执行者)

    console.log(new Promise(function(resolve,reject){})); 
    // Promise {<pending>}
    // [[Prototype]]: Promise
    // catch: ƒ catch()
    // constructor: ƒ Promise()
    // finally: ƒ finally()
    // then: ƒ then()
    // Symbol(Symbol.toStringTag): "Promise"
    // [[Prototype]]: Object
    // [[PromiseState]]: "pending"
    // [[PromiseResult]]: undefined
    
  2. 同步执行

    new Promise(function(resolve,reject){
    	console.log('promise');
    });
    console.log(1);
    // 'promise' 1
    
  3. 三种状态

    1. panding(进行中)
    2. fufilled(也叫resolve)(已成功)
    3. reject(已失效)

    两个过程:padding - resolve、padding - reject,promise的resolve、reject代表的是这两个过程

  4. 两个特征

    1. 对象的状态不受外界影响(唯一能影响的就是当前它所代表的异步事件)
    2. 状态不可逆(promise固化以后,再对promise对象添加回调,是可以直接拿到这个结果的,如果说是事件的话,一旦错过了,就是真的错过了)
  5. executor参数

    通过调用resolve、reject方法,改变当前的异步操作的状态,并调用绑定回调函数

  6. 绑定回调函数

    当 promise 的状态发生变化时调用

    通过 then 方法绑定状态为成功或者失败的回调函数

    参数:注册成功回调 / 注册失败回调

    let promise = new Promise((resolve,reject)=>{
       setInterval(function(){
           Math.random()*100 >60 ? resolve('ok'):reject('no');
       },30);
       
    })
    promise.then((val)=>{
        console.log(val);
        
    },(reason)=>{
        console.log(reason);
    })
    //随机的ok no
    

    通过promise代表当前的异步任务,当异步任务完成以后调用相应的方法来改变promise当前的状态,并调用promise通过.then的方式绑定的回调函数

  7. 执行顺序

    promise里面是同步执行

    而resolve、reject是promise的异步操作,执行会改变当前promise的状态,调用绑定的回调函数

    let promise = new Promise((resolve,reject)=>{
          console.log(0);
          resolve('1'); // 异步操作,调用的回调属于异步任务
           
       })
        promise.then((val)=>{
            console.log(val);
            
        },(reason)=>{
            console.log(reason);
        })
    console.log(2);
    // 先执行主线程任务 0 2 再执行任务队列当中的 1
    

    当有两个异步任务时

    setTimeout(function(){
        console.log('SET TIME');
    },30);
    let promise = new Promise((resolve,reject)=>{
      console.log(0);
      resolve('1');
    });
    promise.then((val)=>{
        console.log(val);
    },(reason)=>{
        console.log(reason);
    });
    console.log(2);
    //0 2 1 SET TIME
    

    JS异步代码中,

    分为宏任务(宏任务队列),

    微任务(微任务队列):promise、process.nextTick() 优先级更高(除了这两个其它都是宏任务)

    Promise.resolve().then(()=>{ //在executor里面调用是等效的
        console.log('promise1');
        setTimeout(()=>{
            console.log('setTime2'); 
        })
    })
    setTimeout(()=>{
        console.log('setTime1');
        Promise.resolve().then(()=>{
            console.log('promise2');
            
        })
    })
    //第一轮:promise1 setTime1 第二轮:promise2 setTime2
    
  8. 链式调用

    then默认返回promise对象,所以可以链式调用

    let promise = new Promise(function(resolve,reject){
        setInterval(function(){
            Math.random * 100 > 60 ? resolve('ok') : reject('no');
        },30)
    })
    promise.then((val)=>{
        console.log(val)
    },(reason)=>{
        console.log(reason)
    }).then((val)=>{ // 因为上一个默认promise没有传值,所以这里val是undefined
        console.log(val);
    },(reason)=>{
        console.log(reason);
    })
    //no undefined
    

    第一次then的返回值作为下一次then的执行参数

    let promise = new Promise(function(resolve,reject){
        setInterval(function(){
            Math.random() * 100 > 60 ? resolve('ok') : reject('no');
        },30)
    });
    promise.then((val)=>{
        console.log(val)
        return 3;
    },(reason)=>{
        console.log(reason)
        return 2;
    }).then((val)=>{
        console.log(val);
    },(reason)=>{
        console.log(reason);
    });
    // ok 3 or no 2
    

    如果第一次就return一个新的Promise 那么就会调用第二个then,参数就自动获取resolve中的了

    let promise = new Promise(function(resolve,reject){
        setInterval(function(){
            Math.random() * 100 > 60 ? resolve('ok') : reject('no');
        },30)
    })
    promise.then((val)=>{
        console.log(val)
        return new Promise((resolve,reject)=>{
            resolve('newPromise')
        })
    },(reason)=>{
        console.log(reason)
        return new Promise((resolve,reject)=>{
            reject('rejectPromise')
        })
    }).then((val)=>{
        console.log(val);
    },(reason)=>{
        console.log(reason);
    })
    //ok newPromise or no rejectPromise
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值