• 异步解决方案


    在js中任务的执行模型有两种:同步模式异步模式

    • 同步模式:后一个任务B等待前一个任务A结束后,再执行。任务的执行顺序和任务的排序顺序是一致的。

    • 异步模式:每一个任务有一个或多个回调函数,前一个任务A结束后,不是执行后一个任务B,而是执行任务A的回调函数。而后一个任务B是不等任务A结束就执行。任务的执行顺序,与任务的排序顺序不一致。

    异步在实现上,依赖一些特殊的语法规则。从整体上来说,异步方案经历了如下的四个进化阶段:回调函数 —> Promise —> Generator —> async/await。其中 Promise、Generator 和 async/await 都是在 ES2015 之后,慢慢发展起来的、具有一定颠覆性的新异步方案。

    “回调函数” 时期

    事件监听:任务的执行顺序与代码的编写顺序无关,只与点击事件有没有被触发有关

    发布订阅:任务执行的时机和某一事件的发生紧密关联了起来。

     

    回调函数:回调地狱导致可读性和可维护性被破坏

     Promise 

     说说你理解的 Promise(三种状态,两个过程)

    Promise 对象是一个代理对象。它接受你传入的 executor(执行器)作为入参,允许你把异步任务的成功和失败分别绑定到对应的处理方法上去。一个 Promise 实例有三种状态:

    pending 状态,表示进行中。这是 Promise 实例创建后的一个初始态;
    fulfilled(resolved) 状态,表示成功完成。这是我们在执行器中调用 resolve 后,达成的状态;
    rejected 状态,表示操作失败、被拒绝。这是我们在执行器中调用 reject后,达成的状态;
    Promise实例的状态是可以改变的,但它只允许被改变一次。当我们的实例状态从 pending 切换为 rejected 后,就无法再扭转为 fulfilled,反之同理。当 Promise 的状态为 resolved 时,会触发其对应的 then 方法入参里的 onfulfilled 函数;当 Promise 的状态为 rejected 时,会触发其对应的 then 方法入参里的 onrejected 函数。

    Promise 常见方法有哪些?各自是干嘛的?

    Promise的方法有以下几种:
    Promise.all(iterable):这个方法返回一个新的 promise 对象,该 promise 对象在 iterable 参数对象里所有的 promise 对象都成功的时候才会触发成功,一旦有任何一个 iterable 里面的 promise 对象失败则立即触发该 promise 对象的失败。

    var p1 = Promise.resolve('1号选手');
    var p2 = '2号选手';
    var p3 = new Promise((resolve, reject) => {
      setTimeout(resolve, 100, "3号选手");
    }); 
    Promise.all([p1, p2, p3]).then(values => { 
      console.log(values); //  ["1号选手", "2号选手", "3号选手"]
    });

    使用场景:执行某个操作需要依赖多个接口请求回的数据,且这些接口之间不存在互相依赖的关系。这时使用Promise.all(),等到所有接口都请求成功了,它才会进行操作。

    let promise1 = new Promise((resolve) => {
            setTimeout(() => {
                resolve('promise1操作成功');
                console.log('1')
            }, 3000);
        });
       
        let promise2 = new Promise((resolve) => {
            setTimeout(() => {
                resolve('promise1操作成功');
                console.log('2')
            }, 1000);
        });
    
        Promise.all([promise1, promise2]).then((result) => {
            console.log(result);
        });

    Promise.race(iterable):当 iterable 参数里的任意一个子 promise 被成功或失败后,父 promise 马上也会用子 promise 的成功返回值或失败详情作为参数调用父 promise 绑定的相应处理函数,并返回该 promise 对象。

    var p1 = new Promise(function(resolve, reject) { 
        setTimeout(resolve, 100, "1号选手"); 
    });
    var p2 = new Promise(function(resolve, reject) { 
        setTimeout(resolve, 50, "2号选手"); 
    });
    
    // 这里因为 2 号选手返回得更早,所以返回值以 2号选手为准
    Promise.race([p1, p2]).then(function(value) {
      console.log(value); //  "2号选手"
    });
    let promise1 = new Promise((resolve) => {
            setTimeout(() => {
                resolve('promise1操作成功');
                console.log('1')
            }, 3000);
        });
    
        let promise2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('promise1操作失败');
                console.log('2')
            }, 1000);
        });
    
        Promise.race([promise1, promise2])
            .then((result) => {
                console.log(result);
            })
            .catch((error) => {
                console.log(error);
            })

     1s后,promise2进入rejected状态,由于一个实例的状态发生了变化,所以Promise.race()就立刻执行了,其他实例中再发生变化,它也不管了。

    • Promise.reject(reason): 返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法
    • Promise.resolve(value):它返回一个 Promise 对象,但是这个对象的状态由你传入的value决定,情形分以下两种:
      • 如果传入的是一个带有 then 方法的对象(我们称为 thenable 对象),返回的Promise对象的最终状态由then方法执行决定
      • 否则的话,返回的 Promise 对象状态为 fulfilled,同时这里的 value 会作为 then 方法中指定的 onfulfilled 的入参

    真题分析

    Promise 中的处理函数是异步任务

    const promise = new Promise((resolve,reject) =>{
            console.log(1);
            resolve();
            console.log(2);
        })
        promise.then(()=>{
            console.log(3);
        })
        console.log(4);

     then 方法中传入的任务是一个异步任务。resolve() 这个调用,作用是将 Promise 的状态从 pending 置为 fulfilled,这个新状态会让 Promise 知道“我的 then 方法中那个任务可以执行了”——注意是”可以执行了“,而不是说”立刻就会执行“。毕竟作为一个异步任务,它的基本修养就是要等同步代码执行完之后再执行。所以说数字 3 的输出排在最后。

    Promise 对象的状态只能被改变一次

    const promise = new Promise((resolve,reject) =>{
            resolve('第1次resolve')
            console.log('resolve后的普通逻辑1');
            reject('error')
            resolve('第2次resolve');
            console.log('resolve后的普通逻辑2');
        })
        promise.then((res)=>{
            console.log('then:',res);
        }).catch((err)=>{
            console.log('catch',err);
        })

     这段代码里,promise 初始状态为 pending,我们在函数体第一行就用 resolve 把它置为了 fulfilled 态。这个切换完成后,后续所有尝试进一步作状态切换的动作全部不生效,所以后续的 reject、resolve大家直接忽略掉就好;需要注意的是,我们忽略的是第一次 resolve 后的 reject、resolve,而不是忽略它身后的所有代码。因此 console.log(‘resolve后的普通逻辑’) 这句,仍然可以正常被执行。至于这里为啥它输出在 ”then: 第 1 次 resolve“ 的前面,原因和上一题是一样一样的~

    Promise 值穿透

    Promise.resolve(1)
      .then(Promise.resolve(2))
      .then(3)
      .then()
      .then(console.log)

    then 方法里允许我们传入两个参数:onFulfilled(成功态的处理函数)和 onRejected(失败态的处理函数)。

    你可以两者都传,也可以只传前者或者后者。但是无论如何,then 方法的入参只能是函数。万一你想塞给它一些乱七八糟的东西,它就会“翻脸不认人”。

    具体到我们这个题里,第一个 then 方法中传入的是一个 Promise 对象,then 说:”我不认识“;第二个 then 中传入的是一个数字, then 继续说”我不认识“;第四个干脆啥也没穿,then 说”入参undefined了,拜拜“;直到第五个入参,一个函数被传了进来,then 哭了:”终于等到一个我能处理的!“,于是只有最后一个入参生效了。

    在这个过程中,我们最初 resolve 出来那个值,穿越了一个又一个无效的 then 调用,就好像是这些 then 调用都是透明的、不存在的一样,因此这种情形我们也形象地称它是 Promise 的“值穿透”。

     实例

     现在有三个请求,请求A、请求B、请求C。请求C要将请求B的请求回来的数据做为参数,请求B要将请求A的请求回来的数据做为参数。

     回调写法

    $.ajax({
            success:function(res1){
                //------请求B 开始----
                $.ajax({
                    success:function(res2){
                        //----请求C 开始---
                        $.ajax({
                            success:function(res3){
                            }
                        });
                        //---请求C 结束---
                    }    
                });
                //------请求B 结束-----
            }
        });
        //------请求A 结束---------

    promise写法

    let promise = new Promise((resolve, reject) => {
            if (true) {
                //调用操作成功方法
                resolve('操作成功');
            } else {
                //调用操作异常方法
                reject('操作异常');
            }
        });
    
        //then处理操作成功,catch处理操作异常
        promise.then(requestA)
            .then(requestB)
            .then(requestC)
            .catch(requestError);
    
        function requestA() {
            console.log('请求A成功');
            return '下一个是请求B';
        }
    
        function requestB(res) {
            console.log('上一步的结果:' + res);
            console.log('请求B成功');
            return '下一个是请求C';
        }
    
        function requestC(res) {
            console.log('上一步的结果:' + res);
            console.log('请求C成功');
        }
    
        function requestError() {
            console.log('请求失败');
        }

  • 相关阅读:
    [Leetcode] 221. Maximal Square
    [翻译] TensorFlow Programmer's Guide之Frequently Asked Questions(问得频率最多的几个问题)
    [Kaggle] dogs-vs-cats之模型训练
    [Kaggle] dogs-vs-cats之建立模型
    [Kaggle] dogs-vs-cats之制作数据集[1]
    Linux虚拟机Centos 设置固定的静态IP
    linux IP动态变动之后 , 需要做的杂项操作
    GitBlit (1)-- 在linux 安装 GitBlit 并运行
    Linux 安装SVN
    微信开发(3) -- 支付后接收回调信息测试
  • 原文地址:https://www.cnblogs.com/yuyujuan/p/13274447.html
Copyright © 2020-2023  润新知