A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 AreYouGlad 于 2018-1-3 16:26 编辑


控制异步操作流程
普通做法
  • 通过编写嵌套的异步回调来控制代码的执行流程
    [JavaScript] 纯文本查看 复制代码
    setTimeout(function() {        console.log('第一个计时器回调执行,开启第二个');
    
            setTimeout(function() {
                    console.log('第二个计时器回调执行,开启第三个');
    
                    setTimeout(function() {
                            console.log('第三个计时器回调执行');
    
                    }, 2000);
            }, 2000);
    }, 2000);

Promise做法
  • 通过then方法的链式调用控制代码的执行流程
    [JavaScript] 纯文本查看 复制代码
    // 创建一个promise实例[/align]new Promise(function(yes, no) {
            setTimeout(function() {
                    yes();
            }, 2000);
    })
    .then(function() {
        console.log('第一个计时器回调执行,开启第二个');
            return new Promise(function(yes, no) {
                    setTimeout(function() {
                            yes();
                    }, 2000);
            });
    })
    .then(function() {
        console.log('第二个计时器回调执行,开启第三个');
            return new Promise(function(yes, no) {
                    setTimeout(function() {
                            yes();
                    }, 2000);
            });
    })
    .then(function() {
            console.log('第三个计时器回调执行');
    });

promise封装
  • 上面例子setTimeout代码重复写了3遍
  • 对于重复冗余的代码,我们可以考虑封装成一个方法,便于复用
    [JavaScript] 纯文本查看 复制代码
    function timeout(time, data) {        return new Promise(function(yes, no) {
                    setTimeout(function() {
                            yes(data);
                    }, time);
            });
    }
    
    timeout(2000)
    .then(function() {
        console.log('第一个计时器回调执行,开启第二个');
            return timeout(4000);
    });
    .then(function() {
        console.log('第二个计时器回调执行,开启第三个');
            return timeout(4000);
    })
    .then(function() {
        console.log('第三个计时器回调执行');
    });

Promise数据传递
数据传递演示
  • 调用yes与no方法时可以传递一些数据供成功与失败回调使用
    [JavaScript] 纯文本查看 复制代码
    function pmsTimeout(time) {        return new Promise(function(yes, no) {
                    setTimeout(function() {
                            yes('嘿!别睡了,起来嗨!');
                    }, time);
            });
    }
    
    pmsTimeout(2000)
    .then(function(data) {
            console.log(data);  // '嘿!别睡了,起来嗨!'
    });

封装ajax请求
  • 我们把普通异步操作封装成promise版本时,可以让使用者指定数据
    [JavaScript] 纯文本查看 复制代码
    function ajax(config) {        return new Promise(function(yes, no) {
                    Object.assign(config, {
                            success: data => yes(data),
                            error: () => no()
                    });
                $.ajax(config);
            });
    }
    
    let ajaxP = ajax({ url: 'xxx' });
    
    ajaxP.then(function(data) {
            console.log('请求成功');
            console.log(data);
    })
    .cache(function() {
            console.log('请求失败');
    });
    
    // 即便请求结束了,后续也可以通过then拿到数据
    ajaxP.then(function(data) {
        console.log('仍然可以得到前面请求回来的数据');
            console.log(data);
    })

asyncES7
  • 使用它可以以书写同步代码的方式控制Promise执行流程
  • 同步代码阅读起来清晰简单, promise配合async函数使用简直无敌了

定时器例子
  • 下面的例子使用async函数来控制多个定时器的顺序执行
    [JavaScript] 纯文本查看 复制代码
    function timeout(time) {        return new Promise(function(yes, no) {
                    setTimeout(function() {
                            yes();
                    }, time);
            });
    }
    
    // await关键字会等待后面的语句执行完毕后继续向下执行,直到遇到下一个await关键字
    async function test() {
            await timeout(1000);
            console.log('1秒后我才会执行');
    
            await timeout(2000);
            console.log('我要等待上面的代码执行成功后我才执行');
    
            await timeout(3000);
            console.log('以同步方式编写异步代码真是太爽了');
    }
    
    // 调用test异步函数, 体验异步编程幸福生活
    test();

async数据接收
  • 下面范例中使用的fetch方法是浏览器新的标准, 用于发送ajax请求
  • fetch特点是简单好用, 同时调用fetch方法会得到一个promise实例, 可通过then添加成功回调
    [JavaScript] 纯文本查看 复制代码
    async function ajax(url) {    // await关键字还有一个特点, 它可以返回原本需要then才能拿到的数据
            let response = await fetch(url);
            let data =  response.ok && await response.json();
            console.log('可以在这里使用data数据了');
    }
    
    // 开启幸福生活
    ajax('xxx.json');

async对于promise执行失败的处理
  • 准备工作: 装一个总是执行失败的promise函数, 以此学习如何处理失败
    [JavaScript] 纯文本查看 复制代码
    function timeout(time) {        return new Promise(function(yes, no) {
                    setTimeout(function() {
                            no();
                    }, time);
            });
    }
  • 方式1: try catch语句
    [JavaScript] 纯文本查看 复制代码
    async function test(time) {[/align]    try {
            await timeout(time);
            console.log('成功');
        }catch(e) {
            console.log('失败');
        }
    }
    
    test(2000);
  • 方式2: async方法返回的promise
    [JavaScript] 纯文本查看 复制代码
    async function test(time) {[/align]    await timeout(time);
        console.log('成功');
    }
    
    // async函数调用后会返回一个promise,可以调用then或catch添加成功失败回调
    test(3000).catch(() => console.log('失败'));
  • 方式3: catch方法 - 这种方法会在promise执行失败后仍然向下执行
    [JavaScript] 纯文本查看 复制代码
    async function test(time) {[/align]    await timeout(time).catch(() => console.log('失败'));
        console.log('成功');
    }
    
    test(1000);

async函数返回值
[JavaScript] 纯文本查看 复制代码
async function test(time) {
    await new Promise((yes, no) => yes());
    return 123;
}

test()
.then(data => console.log(data));  // then成功回调可接收async函数的返回值
复习promise与async应用
  • 这里通过jQuery的animate函数来复习巩固promise与async的使用

纯promise
[JavaScript] 纯文本查看 复制代码
function animate(selector, style, time) {[/b]  return new Promise(function(yes, no) {
    $(selector).animate(style, time, () => { yes() });
  });
}

animate('div', { width: 300 }, 2000)
.then(() => { animate('div', { height: 300 }, 1000) })
.then(() => { animate('div', { marginLeft: 500 }, 2000) })
.then(() => { animate('div', { marginTop: 300 }, 1000) })
.catch(() => console.log('发生了未知错误, 动画执行失败了'));


promise结合async
[JavaScript] 纯文本查看 复制代码
function animate(selector, style, time) {[/b]  return new Promise(function(yes, no) {
    $(selector).animate(style, time, () => { yes() });
  });
}

async function divRun() {
    await animate('div', { width: 300 }, 2000);
    await animate('div', { height: 300 }, 1000);
    await animate('div', { marginLeft: 500 }, 2000);
    await animate('div', { marginTop: 300 }, 1000);
}

divRun()
.catch(() => console.log('发生了未知错误, 动画执行失败了'));

1 个回复

正序浏览
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马