搜索

首页  >  问答  >  正文

javascript - 同步方式写异步到底指什么?

同步不就是同步,异步不就是异步吗?同步方式写异步到底指什么?

天蓬老师天蓬老师2784 天前1177

全部回复(4)我来回复

  • 扔个三星炸死你

    扔个三星炸死你2017-07-05 10:54:36

    异步调用对于当前线程来说,是非阻碍的,所以要想知道异步处理是否完成,或者是否出错,通常都是通过事件或回调来实现的,这在 Node.js 比比皆是。Ajax 就是很典型的异步调用,以 jQuery.ajax 为例

    $.getJSON("http://api.youapp.com/resouce1")
        .done(function(jo) {
            console.log("api resouce1 返回的是", jo);
        });

    jQuery 的 Ajax 返回的是 jQuery 的 Promise 对象,一般习惯上我们会使用 done() 回调来处理调用完成之后的事情。但实际它也有标准 Promise 的 then(),所以上面的 done 是可以改成 then 的,但是要注意,done 是以事件的形式注册回调,它返回当前这个 Promise 对象本身,可以链式调用注册若干个回调。而 then 返回的是另一个 Promise 对象(标准 Promise 规范),链式调用的话,每次调用并非作用在同一个 Promise 对象上。

    如果在一个回调中需要进行另一个异步调用,就需要在回调中注册另一个回调。比如要获取某个数据,需要先从 api1 获取某个值,再用这个值去 api2 获取某个资源,再用这个资源中的某个值去 api3 获取这个值,这样的回调写出来会像这样:

    $.getJSON("http://api.youapp.com/resouce1")
        .then(function(jo) {
            $.getJSON("http://api.youapp.com/resouce2?id=" + jo.blaId)
                .then(function(jo2) {
                    $.getJSON("http://api.youapp.com/resouce3?xxx=" + jo2.xxxValue)
                        .then(function(value) {
                            console.log("总算拿到了", value);
                        });
                });
        });

    这才三层……很可怕的形式。这种形式被称为“回调地狱”。

    大家想了很多办法来解决这种问题,Promise 就是其一,但是 Promise 仍然不能完全摆脱这种形式。co 库也是解决方案之一,同样不能完美摆脱。

    不过 ES2017 引入了 async/await,也就是所谓的以同步的形式写异步,比如上面那段代码可以改写成

    
    async function xxx() {
        const jo = await $.getJSON("http://api.youapp.com/resouce1");
        const jo2 = await $.getJSON("http://api.youapp.com/resouce2?id=" + jo.blaId);
        const value = await $.getJSON("http://api.youapp.com/resouce3?xxx=" + jo2.xxxValue);
        console.log("总算拿到了", value);
    }

    async/await 消除了回调,所以看起来跟写非异步(即同步)代码一样。

    参考:

    • 闲谈异步调用“扁平”化

    • 从地狱到天堂,Node 回调向 async/await 转变

    • 理解 JavaScript 的 async/await

    回复
    0
  • PHP中文网

    PHP中文网2017-07-05 10:54:36

    异步时常见回调函数嵌套,形如:

    // 先读取 a
    fs.readFile('a.txt', (a) => {
      // a 读取成功后读取 b
      fs.readFile('b.txt', (b) => {
        // b 读取成功后读取 c
        fs.readFile('c.txt'. (c) => {
          console.log(a + b + c)
        })
      })
    })

    这时出现了回调嵌套,需要一层一层往里套,非常容易出错且不好维护。

    同步方式写异步类似于:

    function * asyncWrapper () {
      const a = yield read('a.txt')
      const b = yield read('b.txt')
      const c = yield read('c.txt')
      console.log(a + b + c)
    }
    // 使用形如 co 的库自动执行异步逻辑
    co(asyncWrapper)

    这时候异步业务逻辑就通过正常的同步方式实现了。

    回复
    0
  • 我想大声告诉你

    我想大声告诉你2017-07-05 10:54:36

    同步方式写异步指得是代码的组织形式而已。使用async/await可以实现同步方式写异步,看下面代码:

    const testAsync = async () => {
      const t = await f();
      console.log(t);
    };
    
    testAsync();

    f是一个异步操作,如果不使用async/await,直接同步的方式打印t,结果肯定是undefined;使用async/await之后,代码看上去形式还是同步的,但是里面是先执行异步操作f,再打印t的

    回复
    0
  • 伊谢尔伦

    伊谢尔伦2017-07-05 10:54:36

    楼上两个答案足矣

    回复
    0
  • 取消回复