zoukankan      html  css  js  c++  java
  • promise

    Promise按照用途来解释:

    主要用于异步运算。

    可以将异步操作队列化,按照期望的顺序执行,返回符合期望的结果。

    可以在对象之间传递和操作Promise,帮助我们处理队列。

    Promise产生的原因:

    Javascript中包含大量异步操作。

    创造它的首要目标是操作DOM。

    所以,Javascript的操作大多是异步的。

    浏览器中的Javascript

    异步操作以 事件为主。

    回调主要出现在Ajax和File API 。

    异步回调的问题:

    嵌套层次很深,难以维护。

    无法正常使用return和throw。

    无法正常检索堆栈信息。

    多个回调之间难以建立联系。

    下面是Promise的模型简介:

    new Promise(
        /*执行器executor*/
        function (resovle, reject) {
            resovle();
            reject();
        }
    )
        .then(function A() {
            //成功,下一步
        }, function B() {
            //失败,做响应处理
        })
    

    从上面代码可以看出:

    Promise 是一个代理对象,它和原先要进行的操作并无关系。

    它通过引入一个回调,避免更多的回调。

    Promise有3个状态:

    • pendding[待定] 初始状态
    • fulfilled[实现]操作成功
    • rejected[被否决]操作失败

    当Promise状态发生变化 ,就会触发.then() 里的相应函数处理后续步骤。

    Promise状态一经改变,不会再变。

    接下来这张图片是Promise执行的过程

    image-20200307111725436

    每个then执行完了之后,都会返回一个Promise对象,然后再调用下一个then,直到所有的then都处理完。

    最简单的实例:

    console.log('here we go');
    new Promise(resolve => {
        console.log("execute start");
        setTimeout(() => {
            resolve('hello');
        }, 2000)
    }).then(value => {
        console.log(value + ' resolve world');
    });
    

    代码的执行结果为

    here we go

    execute start

    hello resolve world

    这样可以直观的看出then函数是等执行器执行结束才会执行的。

    两步执行的范例:分2次,顺序依次执行

    console.log('here we go');
    new Promise(resolve => {
        console.log("execute start");
        setTimeout(() => {
            resolve('hello');
        }, 2000)
    }).then(value => {
        console.log(value + ' resolve world');
        return new Promise(resolve => {
            setTimeout(() => {
                resolve('world');
            }, 2000)
        })
    }).then(value => {
        console.log(value + ' world');
    });
    

    代码的执行结果为:

    here we go

    execute start

    hello resolve world

    world world

    从上面例子可以看出,promise是会顺序执行每个then的。

    当promise里面的状态一旦发生变化,会调用then,

    然后then会生成一个新的promise,每次promise其实传递的只有一个状态,(resolve或者reject),

    紧接着then会接收到这个状态函数里面传递的数值。

    promise用自己的回调解决了多个回调函数嵌套的问题

    假设一个Promise已经完成了,再.then()会怎样?

    console.log('start');
    let promise = new Promise(resolve => {
        setTimeout(() => {
            console.log('the promise fulfilled');
            resolve('hello, world');
        }, 1000);
    });
    
    setTimeout(() => {
        promise.then(value => {
            console.log(value);
        })
    }, 3000)
    

    输出结果为:

    start

    the promise fulfilled

    hello, world

    在任何一个地方生成了promise队列后,如果我们的队列是先进先出的状态,队列会按顺序执行,后面追加的then,也会接受到前面promise返回的值。

    假设在.then()的函数里面不返回新的Promise,会怎样?

    console.log('start');
    new Promise(resolve => {
        setTimeout(() => {
            resolve('hello');
        })
    })
        .then(value => {
            console.log(value);
            console.log('everyone');
            (function () {
                return new Promise(resolve => {
                    setTimeout(() => {
                        console.log('Mr laure');
                        resolve('Merry XmaS');
                    }, 2000);
                })
            }())
            return false;
        })
        .then(value => {
            console.log(value + ' world');
        });
    

    输出结果为:

    start

    hello
    everyone
    false world

    Mr laure

    上面的代码可以看出,第一个then函数里面有一个立即执行的函数,是在2s之后返回一个promise对象,但是先返回了false,就会调用第2个then;

    因为第2个then没有返回新的值,返回的promise是在立即执行的函数里返回的,而不是在then的响应函数里面返回的,then返回的promise实例就没有等待里面的函数完成,而是在返回了false之后,直接调用了下面那个then,false被传递给了第2个then函数。

    在promise里面,如果不直接返回一个promise实例,会默认执行下一个环节,即使返回了false,如果没有传递值,第2个then里面的value就是undefined,仍然不影响promise往下执行。

    引出.then()

    .then()接收两个函数作为参数,分别代表fulfilled和rejected

    .then()返回一个新的Promise实例,所以它可以链式调用

    当前面的Promise状态改变时,.then()根据其最终状态,选择特定的状态响应函数执行。

    状态响应函数可以返回新的Promise,或者其他值。

    如果返回新的Promise,那么下一级.then() 会在新Promise状态改变之后执行。

    如果返回其他任何值,则会立刻指向下一级.then()

    then的嵌套

    因为.then()返回的还是Promise实例。

    会等里面的.then()执行完,再执行外面的。

    对于我们来说,此时最好将其展开,会更好读。

    如下代码:then里面又嵌套几个then

    console.log('start');
    new Promise(resolve => {
        setTimeout(() => {
            resolve(100);
        }, 1000)
    })
        .then(value => {
            return new Promise(resolve => {
                console.log('1-1');
                setTimeout(() => {
                    resolve(110);
                }, 1000)
            })
                .then(value => {
                    console.log('step 1-2');
                    return value;
                })
                .then(value => {
                    console.log('step 1-3');
                    return value;
                });
        })
        .then(value => {
            console.log(value + ' world');
        });
    

    输出结果为:

    start

    1-1

    step 1-2

    step 1-3

    110 world

    看结果可以得出,then里面嵌套的then都是逐步执行的,value会一级一级往下传递,但是不建议then里面嵌套then的方式来写代码,这样感觉看起来不是很友好,展开then里面的then(),下面的方式会友好 一点。

    console.log('start');
    new Promise(resolve => {
        setTimeout(() => {
            resolve(100);
        }, 1000)
    })
        .then(value => {
            return new Promise(resolve => {
                console.log('1-1');
                setTimeout(() => {
                    resolve(110);
                }, 1000)
            })
        })
        .then(value => {
            console.log('step 1-2');
            return value;
        })
        .then(value => {
            console.log('step 1-3');
            return value;
        })
        .then(value => {
            console.log(value + ' world');
        });
    

    接下来,看看下面四种Promise的区别:

    image-20200309111503853

    image-20200309111721464

    image-20200309111804276

    image-20200309112034099

    image-20200309113012322

    错误处理

    Promise会自动捕获内部异常,并交给rejected响应函数处理。

    console.log('start');
    new Promise(resolve => {
        setTimeout(() => {
            throw new Error('bye');
        }, 1000);
    })
        .then(value => {
            console.log(value + 'world')
        })
        .catch(error => {
            console.log('Error:', error.message);
        });
    

    image-20200309113626653

    console.log('start');
    new Promise(resolve => {
        setTimeout(() => {
            throw new Error('bye');
        }, 1000);
    })
        .then(value => {
            console.log(value + 'world')
        }, value => {
            console.log('Error: ', value);
        });
    
    

    推荐用第一种方式,用catch的方式来整体捕获错误。

    错误和then连用

    catch也会返回promise实例,如果返回的过程中没有发生错误的时候,下面的then会依次执行,如果抛出了异常,下面的then会忽略

    注意:强烈建议在所有队列最后都加上.catch(),以避免漏掉错误处理造成意想不到的问题。

    image-20200309114323336

    Promise常用函数:

    Promise.all() 函数和.map()函数连用

  • 相关阅读:
    贺铿:中国多年来楼市调控不合理又不合法
    Ubuntu12.04下arm交叉编译环境的建立
    Android2.3.7源码结构分析
    【开源推荐】AllJoyn:打造全球物联网的通用开源框架
    Ubuntu12.04安装JDK6
    ubuntu12.04升级后找不到共享目录
    Windows Embedded Compact 7新特性
    Windows Embedded Compact 2013 安装体验
    巴登的故事
    h5调用底层接口的一些知识
  • 原文地址:https://www.cnblogs.com/zdjBlog/p/12564388.html
Copyright © 2011-2022 走看看