异步编程的解决方案

[toc]

同步编程与异步编程

同步编程

1
2
3
4
5
console.log("给1打电话");// 1
console.log("给2打电话");// 2
console.log("给3打电话");// 3
console.log("给4打电话");// 4
console.log("给5打电话");// 5

异步编程
例如,setTimeout 就是一个异步方法 不会受到一个卡顿影响到其他的卡顿

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 给4发短信 1 2 5 3
setTimeout(() => {
console.log("给1发短信");
}, 200);
setTimeout(() => {
console.log("给2发短信");
}, 500);
setTimeout(() => {
console.log("给3发短信");
}, 2000);
setTimeout(() => {
console.log("给4发短信");
}, 100);
setTimeout(() => {
console.log("给5发短信");
}, 900);

异步获取数据的方法

AJAX 与服务器通信,异步获取数据。现阶段还没接触到 AJAX,试一下其他方法。
首先先let target = "hello world";,假设只能通过 getData 来获取数据(target)。

  • 方案 1:回调函数
    先回顾一下回调函数。函数可以作为一个参数在传递到另一个函数中。setTimeout、防抖和节流经常用到。函数体在完成某种操作后由内向外调用某个外部函数。

    1
    2
    3
    4
    5
    6
    function fun(fn) {
    fn();
    }
    fun(() => {
    console.log("我是回调函数。")
    });// 我是回调函数。

    回归本题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    let target = "hello world";

    function getData() {
    // // 同步的写法
    // return target;

    // // 异步写法测试 这样写返回的undefined,因为return只能返回同步的数据
    // setTimeout(() => {
    // return target
    // }, 500);

    // 通过回调函数输出hello world
    setTimeout(() => {
    fn(target);
    }, 500);
    }

    // getData()穿递的参数是fn(),然后fn()传递的参数是d,d就是target.
    getData((d) => {
    console.log(d);
    }); // hello world

    为了解决 JS 的异步执行回调地狱问题,人们又发明了一些其他解决方案,比如说 Promises、Async functions 等等。

  • 方案 2:Promise 对象获取数据

    Promise 是 ES2015 提供的一个内置对象。Promise 就是用来解决异步问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let target = "hello promise"
    // 创建一个promise对象, resolve是一个函数
    let p = new Promise((resolve) =>{
    setTimeout(() => {
    resolve(target); // 把target作为参数传递给resolve函数给传递出来,并把promise对象赋给p
    }, 500)
    });
    // 利用p获取target
    // promise对象有个then方法,then方法有个参数是一个函数,这个函数里面有个形参,这个形参就是resolve方法传出来的值。
    p.then((d)=> {
    console.log(d);
    })

    回归本题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    let target = "hello world";

    // promise版本的getData,这里是Promise原理
    function getData() {
    return new Promise((resolve) => {
    setTimeout(() => {
    resolve(target);
    }, 500)
    });
    }
    let p = getData(); // getData()的返回值是一个Promise对象
    p.then((data) => {
    console.log(data);
    })
  • 方案 3:async 函数

    await 后面跟着是一个 Promise 对象 等待 promise 对象获取到返回值后才会进行下一个。要在 async 函数中用 await 才有用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    let target = "hello world";
    function getData() {
    return new Promise((resolve) => {
    setTimeout(() => {
    resolve(target);
    }, 500)
    });
    }
    async function fun() {
    // await 后面跟着是一个Promise对象 等待promise对象获取到返回值后才会进行下一个。要在async函数中用await才有用
    let data = await getData(); //getData()的返回值是一个Promise对象
    console.log(data);
    }
    fun(); // hello world

异步编程的解决方案

  1. 回调函数
  2. Promise
  3. async 函数

总结

以上方案是从语法层面来分析解决异步的问题。
后续将会学习 Ajax,异步获取服务端数据,需要用到大量的异步编程。

课后练习

熟练使用回调函数、Promise 和 async 函数解决异步问题。

  • 回调函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let str = "Hello world";

    function getData(fn) {
    setTimeout(() => {
    fn();
    }, 500)
    };
    getData(() => {
    console.log(str);// Hello world
    })
  • Promise 对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // Promise
    let str = "Hello world";

    function getData() {
    return new Promise((resolve)=>{
    setTimeout(()=>{
    resolve(str);
    },500)
    })
    }

    let p = getData();
    p.then((d)=>{
    console.log(d);
    })
  • async 函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Async
    let str = "Hello world";

    function getData(){
    console.log(str);
    }

    async function fun() {
    let data = await getData();
    }
    fun();

欢迎关注我的其它发布渠道