ES6-19【promise的使用方法和自定义promisify】

一、promise深入

  1. 若在executor里面抛出错误,promise状态会直接更改为reject

    let promise = new Promise(function(resolve,reject){
      resolve(a); // 还没来得及执行就抛出了错误,将状态更改为reject,然后触发回调
    })
    promise.then((val)=>{
        console.log('resolve: '+val)
    },(reason)=>{
        console.log('reject: '+reason)
    })
    // reject: a is not defined
    
  2. then的简写

    至少有一个参数,不指定用null占位

    promise.then(null,(reason)=>{
        console.log('reject: '+reason)
    });
    //等同于
    promise.catch(function(reason){
    	console.log('reject: '+reason)
    })
    
  3. catch

    1. 基本使用

      也可以捕获异常

      let promise = new Promise(function(resolve,reject){
        resolve(a);
      })
      promise.catch(function(reason){
          console.log(reason)
      });
      // ReferenceError: a is not defined
      
    2. 语义化写法

      当需要捕获异常的时候,推荐使用第二种写法

      promise.then(function(){
      
      },function(){
      
      });
      // 推荐
      promise
        .then(function(){
      
      })
        catch(function(){
      
      })
      
    3. 特性

      1. 冒泡的特性
      2. 状态固化之后,无法捕获异常
      3. 链式调用 then() 的时候,如果什么参数都不传会被直接忽略
      let promise = new Promise(function(resolve,reject){
        resolve(a);
      })
      promise.then(function(val){
          console.log(val);
      }).then().then().catch(function(err){
          console.log(err);
      })
      // ReferenceError: a is not defined
      
  4. promise固化

    如果promise状态发生变化,就意味着状态不会再发生改变

    let promise = new Promise(function(resolve,reject){
      resolve('ok'); 
      console.log(a); // 这里也执行了,但由于状态已经固化了,所以catch捕获不到
    })
    promise.then((val)=>{
        console.log(val);
    }).catch((err)=>{
        console.log(err);
    });
    //ok
    
  5. 状态依赖

    每一个promise代表的是一个异步操作,每个异步操作都有相应的状态,那么在有多个promise嵌套的情况下,状态又是怎样传递的呢?

    当executor的resolve、reject的参数是另一个promise的时候,那么当前promise的状态,就取决于另一个promise的状态

    let p1 = new Promise((resolve,reject)=>{ //也是同步执行
      setTimeout(function(){
          reject(new Error('fail'));
      },3000);
    });
    let p2 = new Promise((resolve,reject)=>{
      setTimeout(function(){
          resolve(p1);
      },1000);
    });
    p2.then(result=>console.log(result))
      .catch(err=>console.log(err));
    //Error: fail
    

    当前p2的状态依赖于p1,就会导致p2自己的状态无效,它的状态取决于p1的状态

  6. resolve/reject不会终止executor执行

    const p1 = new Promise((resolve,reject)=>{
    	//resolve(1);
    	reject(new Error()); //微任务
    	console.log(2);
    });
    p1.then(res=>console.log(res))
      .catch(err=>console.log(err));
    console.log(3);
    //2 3 Error
    
  7. race/all管理异步的关系

    promise通过race、all管理异步之间的关系

    1. all

      批量处理多个异步操作,返回值是promise对象

      参数是具有iterator接口的对象(数组),里面是相应的promise

      只有所有promise状态为成功情况下,才会触发成功回调

      成功回调参数是一个数组,其顺序与iterable里promise顺序一致

      const fs = require('fs');
      let promise1 = new Promise((resolve,reject)=>{
      	fs.readFile('./name.txt','utf-8',function(err,data){
      		if(err){
      			console.log(err);
      		}
      		resolve(data);
      	});
      });
      let promise2 = new Promise((resolve,reject)=>{
      	fs.readFile('./number.txt','utf-8',function(err,data){
      		if(err){
      			console.log(err);
      		}
      		resolve(data);
      	});
      });
      let promise3 = new Promise((resolve,reject)=>{
      	fs.readFile('./score.txt','utf-8',function(err,data){
      		if(err){
      			console.log(err);
      		}
      		resolve(data);
      	});
      });
      const p  = Promise.all([promise1,promise2,promise3]); //返回值是promise对象
      p.then(res=>console.log(res));
      //[ './number.txt', 'score.txt', '90' ]
      

      只要有一个promise状态为失败,就会触发失败回调

      如果全部promise状态都为失败,则只触发iterable里第一个promise状态为失败的回调,其余直接忽略

      let promise1 = new Promise((resolve,reject)=>{
          setTimeout(function(){
              reject('promise1: 1000ms')
          },1000)
      })
      let promise2 = new Promise((resolve,reject)=>{
          setTimeout(function(){
              reject('promise2: 2000ms')
          },2000)
      })
      let promise3 = new Promise((resolve,reject)=>{
          setTimeout(function(){
              reject('promise3: 3000ms')
          },3000)
      })
      let p = Promise.all([promise1,promise2,promise3]);
      p.then(res=>console.log(res)
      ).catch((error)=>{
          console.log(error);
      })
      //失败回调:promise1:1000ms   后面直接忽略
      
    2. race

      批量处理多个异步操作,返回值是promise对象

      任意一个promise状态为成功或失败,就会触发相应的回调,其余直接忽略

      let promise1 = new Promise((resolve,reject)=>{ 
          setTimeout(function(){
          	//resolve('promise1: 1000ms');
              reject('promise1: 1000ms');
          },1000)
      })
      let promise2 = new Promise((resolve,reject)=>{
          setTimeout(function(){
          	//resolve('promise2: 2000ms');
              reject('promise2: 2000ms');
          },2000)
      })
      let promise3 = new Promise((resolve,reject)=>{
          setTimeout(function(){
          	//resolve('promise3: 3000ms');
              reject('promise3: 3000ms');
          },3000)
      });
      let p = Promise.race([promise1,promise2,promise3]);
      p.then(res=>console.log(res)
      ).catch((error)=>{
          console.log(error);
      });
      //promise1:1000ms  不管成功或失败都返回这个,因为它最先完成  其余直接忽略
      
  8. 构造器上的resolve/reject

    1. thenable

      绑定了then方法的对象就是thenable,用于转换成promise对象

    2. resolve —— 转换成功promise对象

      返回一个promise对象,当前promise的状态取决于resolve的参数

      1. 是一个thenable

        let obj = {
            then:function(resolve,reject){
                resolve(42);
            }
        }
        let p1 = Promise.resolve(obj);
        
        p1.then(function(value){
            console.log(value);
            
        });
        //42
        
      2. 字符串

        let p1 = Promise.resolve('hello');
        p1.then(res=>{
            console.log(res)
        });
        //hello
        
      3. 没有参数

        let p1 = Promise.resolve();
        p1.then(res=>{
            console.log(res)
        });
        //undefined
        
    3. reject —— 转换失败promise对象

      返回一个promise对象,当前promise的状态取决于resolve的参数

      1. thenable(不要用)

        let obj = {
            then: function(resolve, reject) {
                reject(new Error('hello'));
            }
        }
        let p1 = Promise.reject(obj);
        
        p1.then(null, function(value) {
            console.log(value);
        
        });
        //{ then: [Function: then] }   what the hell? 所以不要用
        
      2. 字符串

        let p1 = Promise.reject('hello');
        p1.then(null,res=>{
            console.log(res)
        });
        //hello
        
      3. 不传参

        let p1 = Promise.reject();
        p1.then(null,res=>{
            console.log(res)
        });
        //undefined
        
  9. 函数Promise化

    将异步函数用promise包装一遍

    const fs = require('fs');
    function readFile(path){
        return new Promise((resolve,reject)=>{
            fs.readFile(path,'utf-8',(err,data)=>{
                if(data){
                    resolve(data);
                }
            })
        })
    }
    readFile('./name.txt')
    .then(data => readFile(data))
    .then(data => readFile(data))
    .then(data => console.log(data));
    //99
    

二、promisify

  1. promisify概念

    能够将所有函数promise化的方法

  2. promisify实现(node)

    const fs = require('fs');
    function promisify(func){ 
        return function(...arg){ // 1.返回promise化的方法,传入需promise化的方法
            return new Promise((resolve,reject)=>{ // 2.调用promise化的方法,需传入相应参数
                func(...arg,(err,data)=>{ // 3.根据参入的方法和参数,执行相应的方法
                    if(err){
                        reject(err);
                    }else{
                        resolve(data)
                    }
                })
            })
        }
    }	
    let readFile = promisify(fs.readFile); // 第一步:传入需promise化的方法
    readFile('./name.txt','utf-8') 		   // 第二步:需传入相应参数
        .then(data=>readFile(data,'utf-8'))
        .then(data=>readFile(data,'utf-8'))
        .then(data=>console.log(data)); //99
    
  3. node工具函数中也提供了promisify

    const util = require('util');
    let readFile = util.promisify(fs.readFile);
    // 也能实现
    readFile('./name.txt','utf-8')
        .then(data=>readFile(data,'utf-8'))
        .then(data=>readFile(data,'utf-8'))
        .then(data=>console.log(data)); //99
    
  4. 优化node提供的promisify

    把fs上的所有方法转成promisify方法

    const fs = require('fs');
    const util = require('util');
    let readFile = util.promisify(fs.readFile);
    let readdir = util.promisify(fs.readdir);
    let writeFile = util.promisify(fs.writeFile);
    
    //每次使用前都要传入promise化的方法,比较麻烦,本次优化就是解决这个问题
    
    function promisify(func){ 
        return function(...arg){ 
            return new Promise((resolve,reject)=>{
                func(...arg,(err,data)=>{ 
                    if(err){
                        reject(err);
                    }else{
                        resolve(data)
                    }
                })
            })
        }
    }	
    function promisifyAll(obj){
        for(let [key,fn] of Object.entries(obj)){ // 注意:这里for...of本不能遍历obj,但这里用Object.entries把obj转成了键和值的数组,所以可以迭代
            if(typeof fn === 'function' ){
                obj[key+'Async'] = promisify(fn);
            }
        }
    }
    promisifyAll(fs)
    fs.readFileAsync('./name.txt','utf-8')
    .then(data=>readFileAsync(data,'utf-8'))
    .then(data=>readFileAsync(data,'utf-8'))
    .then(data=>console.log(data));
    //99
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值