资讯专栏INFORMATION COLUMN

JavaScript 中优雅的实现顺序执行异步函数

monw3c / 1130人阅读

摘要:顺序执行异步函数异步为带来非阻塞等优势的同时,同时也在一些场景下带了不便,如顺序执行异步函数,下面总结了一些常用的方法。

火于异步

1995年,当时最流行的浏览器——网景中开始运行 JavaScript (最初称为 LiveScript)。 1996年,微软发布了 JScript 兼容 JavaScript。随着网景、微软竞争而不断的技术更新,在 2000年前后,JavaScript 相关的技术基础准备就绪。 随后到 2005 年前后,以 Google 为首开始重视使用 AJAX(即 Asynchronous JavaScript and XML),使得复杂的网页交互体验接近桌面应用。

然后,随着 Web 应用变得越来越复杂 ,JavaScript 的生态和重要性也日益提升,YUI、prototype.js、jQuery 等各种库相应登场,随之而来就到了 JavaScript 的繁荣期。

2008年,Google 发布了 JavaScript 引擎 V8 大大改善了 JavaScript 的执行速度,进一步推动了 JavaScript 的繁荣,也为 JavaScript 进军服务器端打下了基础(如:Node.js)。

顺序执行异步函数

异步为 JavaScript 带来非阻塞等优势的同时,同时也在一些场景下带了不便,如:顺序执行异步函数,下面总结了一些常用的方法。

1. "回调地狱"

随着应用复杂度几何式增加,我们可能遇到下面“回调地狱”式的代码。

// 第一个任务
function task1 (callback) {
  setTimeout(() => {
    console.log("1", "我是第一个任务,必须第一个执行");
    callback && callback(1);
  }, 3000);
}

// 第二个任务
function task2 (callback) {
  setTimeout(() => {
    console.log("2", "我是第二个任务");
    callback && callback(2);
  }, 1000);
}

// 第三个任务
function task3 (callback) {
  setTimeout(() => {
    console.log("3", "我是第三个任务");
    callback && callback(3);
  }, 1000);
}

// 所有任务
function allTasks () {
  task1((cb1) => {
    if (cb1) {
      task2((cb2) => {
        if (cb2) {
          task3((cb3) => {
            if (cb3) {
              // 顺序完成所有任务
            }
          })
        }   
      });
    }
  });
}

allTasks();

/**
 * 3秒后
 * 1 我是第一个任务,必须第一个执行
 * 1秒后
 * 2 第二个任务
 * 1秒后
 * 3 第三个任务
 */
2. Promise

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

为了避免“回调地狱”带来的复杂性和不易阅读,ES6 推出了 Promise。这次实现起来简单多了,但还存在 Promise 中嵌套多层 Promise 的问题,似乎又回到了类似“回调地狱”的问题上。

new Promise(resolve => {
  setTimeout(() => {
    console.log("1", "我是第一个任务,必须第一个执行");
    resolve(1);
  }, 3000);
}).then((val) => {

  new Promise(resolve => {
    setTimeout(() => {
      console.log("2", "我是第二个任务");
      resolve(2);
    }, 1000);
  }).then(val => {
    setTimeout(() => {
      console.log("3", "我是第三个任务");
    }, 1000); 
  });

});
/**
 * 3秒后
 * 1 我是第一个任务,必须第一个执行
 * 1秒后
 * 2 第二个任务
 * 1秒后
 * 3 第三个任务
 */
3. Await、Async
确保支持,详细见:https://caniuse.com/#search=async

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await

为了更易书写和阅读来实现顺序执行异步函数,ES2017 新增了 awaitasync。这次书写体验非常的棒,就像写同步代码一样完成了顺序执行异步的需求。

/**
 * 第一个任务
 */
function task1 () {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("1", "我是第一个任务,必须第一个执行");
      resolve("done");
    }, 3000);
  });
}

/**
 * 第二个任务
 */
function task2 () {

  return new Promise(resolve => {
    setTimeout(() => {
      console.log("2", "第二个任务");
      resolve("done");
    }, 1000)
  });
}

/**
 * 第三个任务
 */
function task3 () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("3", "第三个任务");
      reject("error");
    }, 1000);
  });
}

/**
 * 第四个任务
 */
function task4 () {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("4", "第四个任务");
      resolve("done");
    }, 2000);
  })
}

/**
 * 所有任务
 */
async function allTasks () {
  await task1();
  await task2();
  await task3();
  await task4();
}

// 执行任务
allTasks();

/**
 * 3秒后
 * 1 我是第一个任务,必须第一个执行
 * 1秒后
 * 2 第二个任务
 * 1秒后
 * 3 第三个任务
 * Uncaught (in promise) error
 */
完整案例
基于  Node.js,通过 Await 、Async、Promise 实现的顺序执行异步,爬取豆瓣电影截图并按顺序一张张下载图片。

https://github.com/givebest/node-sync-download

参考

《JavaScript编程全解》

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/

转载请注明出处: http://blog.givebest.cn/javascript/2018/04/05/javascript-sync.html

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93978.html

相关文章

  • 谈一谈几种处理JavaScript异步操作办法

    摘要:问题是处理完了,却也引发了自己的一些思考处理的异步操作,都有一些什么方法呢一回调函数传说中的就是来自回调函数。而回调函数也是最基础最常用的处理异步操作的办法。 引言 js的异步操作,已经是一个老生常谈的话题,关于这个话题的文章随便google一下都可以看到一大堆。那么为什么我还要写这篇东西呢?在最近的工作中,为了编写一套相对比较复杂的插件,需要处理各种各样的异步操作。但是为了体积和兼容...

    曹金海 评论0 收藏0
  • Javascript异步编程

    摘要:接下来,我们一起来看看中的异步编程,具体有哪几种。实现异步编程的方法一回调函数上面不止一次提到了回调函数。它是异步编程中,最基本的方法。四对象接下来,我们聊聊与相关的异步编程方法,对象。 showImg(https://segmentfault.com/img/bVbneWy?w=1600&h=1200); 前言 最近,小伙伴S 问了我一段代码: const funB = (value...

    wemall 评论0 收藏0
  • JavaScript 异步

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。写一个符合规范并可配合使用的写一个符合规范并可配合使用的理解的工作原理采用回调函数来处理异步编程。 JavaScript怎么使用循环代替(异步)递归 问题描述 在开发过程中,遇到一个需求:在系统初始化时通过http获取一个第三方服务器端的列表,第三方服务器提供了一个接口,可通过...

    tuniutech 评论0 收藏0
  • 50道JavaScript基础面试题(附答案)

    摘要:事件中属性等于。响应的状态为或者。同步在上会产生页面假死的问题。表示声明的变量未初始化,转换为数值时为。但并非所有浏览器都支持事件捕获。它由两部分构成函数,以及创建该函数的环境。 1 介绍JavaScript的基本数据类型Number、String 、Boolean 、Null、Undefined Object 是 JavaScript 中所有对象的父对象数据封装类对象:Object、...

    huaixiaoz 评论0 收藏0
  • JavaScript:体验异步优雅解决方案

    摘要:但是的的出现碉堡的新朋友,我们可以轻松写出同步风格的代码同时又拥有异步机制,可以说是目前最简单,最优雅,最佳的解决方案了。不敢说这一定是终极的解决方案,但确实是目前最优雅的解决方案 一、异步解决方案的进化史 JavaScript的异步操作一直是个麻烦事,所以不断有人提出它的各种解决方案。可以追溯到最早的回调函数(ajax老朋友),到Promise(不算新的朋友),再到ES6的Gener...

    happyfish 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<