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()函数连用

  • 相关阅读:
    NBUT 1120 Reimu's Teleport (线段树)
    NBUT 1119 Patchouli's Books (STL应用)
    NBUT 1118 Marisa's Affair (排序统计,水)
    NBUT 1117 Kotiya's Incantation(字符输入处理)
    NBUT 1115 Cirno's Trick (水)
    NBUT 1114 Alice's Puppets(排序统计,水)
    188 Best Time to Buy and Sell Stock IV 买卖股票的最佳时机 IV
    187 Repeated DNA Sequences 重复的DNA序列
    179 Largest Number 把数组排成最大的数
    174 Dungeon Game 地下城游戏
  • 原文地址:https://www.cnblogs.com/zdjBlog/p/12564388.html
Copyright © 2011-2022 走看看