zoukankan      html  css  js  c++  java
  • Promise最佳实践(转)

    本文作者:IMWeb dekuchen 原文出处:IMWeb社区 未经同意,禁止转载

    有关Promise的几个问题

    基础概念

    一:什么是Promise

    国内比较流行的看法:

    阮一峰: Promise 对象

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

    Promise 真正的规范,一篇长文。

    https://promisesaplus.com/

    截取几段:

    Terminology

    1. “promise” is an object or function with a then method whose behavior conforms to this specification.
    2. “thenable” is an object or function that defines a then method.
    3. “value” is any legal JavaScript value (including undefined, a thenable, or a promise).
    4. “exception” is a value that is thrown using the throw statement.
    5. “reason” is a value that indicates why a promise was rejected.

    promise-states

    从问题来看

    1. 是否可以使用return 代替 resolve

    不可以,无法实现链式调用,且不符合规范。

    示例:

    const testReturn = (a:boolean):Promise<any> =>{
        return new Promise((resolve,reject)=>{
            if(a){
                return 'this is return';
                resolve('true');
                console.log('this will not be exec');
                throw new Error('error');
            }else{
                reject('false');
            }
        })
    }
    

    执行结果:

     ~/chen/FE/winSep/codes/javascript/es6promise/src � ts-node return.ts
    Promise { <pending> }
    
    1. 无法改变状态
    2. 无法链式调用

    2. 使用throw还是reject?

    答案: 使用reject而不是throw

    示例:不会被catch的throw Error

    const testReturn = (a:boolean):Promise<any> =>{
        return new Promise((resolve,reject)=>{
            if(a){
                resolve('true');
                console.log('this will be exec');
                throw new Error('error');
            }else{
                reject('false');
            }
        })
    }
    
    console.log(testReturn(true));
    

    执行结果

     ~/chen/FE/winSep/codes/javascript/es6promise/src � ts-node return.ts
    this will be exec
    Promise { 'true' }
    

    解释:

    Promise的构造函数,以及被 then 调用执行的函数基本上都可以认为是在 try…catch 代码块中执行的,所以在这些代码中即使使用 throw ,程序本身也不会因为异常而终止。Promise的状态也不会发生改变。

    示例:不使用reject而使用throw

    如果在Promise中使用 throw 语句的话,会被 try...catch 住,最终promise对象也变为Rejected状态。

    var promise = new Promise(function(resolve, reject){
        throw new Error("message");
    });
    promise.catch(function(error){
        console.error(error);// => "message"
    });
    

    运行

    Error: message
    

    代码像这样其实运行时倒也不会有什么问题,但是如果想把 promise 设置为Rejected状态的话,使用 reject 方法则更显得合理。

    所以上面的代码可以改写为下面这样。

    var promise = new Promise(function(resolve, reject){
        reject(new Error("message"));
    });
    promise.catch(function(error){
        console.error(error);// => "message"
    })
    

    总结:如果在Promise中使用 throw 语句的话,会被 try...catch 住,最终promise对象也变为Rejected状态。

    2. Promise的执行时间

    1. resolve后面的代码会不会被执行?

    当没有Error的时候, resolve会将Promise.then放在微任务队列中,当所有的宏任务执行结束的时候,执行微任务队列。
    const testReturn = (a:boolean):Promise<any> =>{
        return new Promise((resolve,reject)=>{
            if(a){
                resolve('exec true');
                console.log('this will be exec');
                // throw new Error('error');
            }else{
                reject('false');
            }
        })
    }
    testReturn(true).then(str=>{
        console.log(str);
    })
    

    执行结果

    this will be exec
    exec true
    
    当有Error的时候,Error后面的代码不会被执行,但是Promise的结果依旧是fulfilled
    const testReturn = (a:boolean):Promise<any> =>{
        return new Promise((resolve,reject)=>{
            if(a){
                resolve('exec true');
                console.log('this will be exec');
                throw new Error('error');
                console.log('this will not be exec')
            }else{
                reject('false');
            }
        })
    }
    
    
    testReturn(true).then(str=>{
        console.log(str);
        // console.log(testReturn)
    }).catch(err=>{
        console.log('err: ',err);
    })
    

    执行结果

    this will be exec
    exec true
    

    当Promise遇到setTimeout

    看例子:

    const testReturn = (a:boolean):Promise<any> =>{
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                if(a){
                    resolve('exec true');
                    console.log('this will be second exec');
                }else{
                    reject('false');
                }
            })
            console.log('this will first be execd');
        })
    }
    
    
    testReturn(true).then(str=>{
        console.log(str);
        // console.log(testReturn)
    }).catch(err=>{
        console.log('err: ',err);
    })
    

    结果

    this will first be execd
    this will be second exec
    exec true
    

    解释:

    时间宏任务队列微任务队列
    1 console.log('this will first be execd')  
    2 setTimeout  
    3   resolve('exec true');//延迟:因为宏任务没有执行完
    4 console.log('this will be second exec');  
       

    最终执行顺序:

    1->2->4(宏任务结束)->3(微任务结束)
    

    async/await 与Promise

    一句话总结:await等的就是一个Promise。如果等的不是Promise,那加了await和不加没区别

    1. 将常规的回调转变为Promise的方法
    function util(args,callback){
        if(err){
            return callback(err);
        }else{
            return callback();
        }
    }
    
    //调用
    util(args,(err)=>{
        if(err){
    
        }else{
    
        }
    })
    //Promisify
    
    function utilPromise(args){
        return new Promise((resolve,reject)=>{
            if(err){
                reject(err)
            }else{
                resolve();
            }
        })
    }
    
    //调用
     utilPromise.then().catch()
    
    1. Promise转换为async/await的方法
    async init(){
        try{
            await utilPromise();//resolve状态
        }catch(e){
            throw new Error(e); //reject状态
        }    
    }

  • 相关阅读:
    JavaScript Basic Memo
    移动端WEB开发备忘录
    重学前端
    roadhog 构建优化
    ES6 memo
    styled-components 背后的魔法
    怎么在多场景下使用不同的 git 账号 commit
    三方登录总结
    Promise 错误处理
    观察者模式 vs 发布-订阅模式
  • 原文地址:https://www.cnblogs.com/sunshq/p/9303909.html
Copyright © 2011-2022 走看看