所谓异步就是指给定了一串函数调用a,b,c,d,各个函数的执行完结返回过程并不顺序为a->b->c->d(这属于传统的同步编程模式),a,b,c,d调用返回的时机并不确定。

对于js代码来说,这种异步编程尤其重要并大量存在,很大的原因是js为单线程模式,其中包含了ui刷新和响应。想像一下,如果我们写了一段js代码,他会发起ajax请求,如果为同步模式,就意味着这时js单线程一直等待这个ajax完成,这期间是不能响应任何用户交互的,这种体验是不可接受的。现在随着服务端js-nodejs的兴起,其超强的异步模式更为nodejs相较于php,java等成熟后端语言的卖点。所有和IO相关的都应该设计成异步模式(比如磁盘IO,网络请求等)

实现异步编程模式可以有以下方式:

1. 回调callback,

看以下nodejs代码:需要注意的是,即使在服务端的nodejs环境中,其运行模型也是单线程模型https://blog.csdn.net/j2IaYU7Y/article/details/81623516

  1. // 遍历目录,找出最大的一个文件
  2. // nodejs的readdir为一个典型的异步调用过程,函数调用马上返回,但是结果却等到目录扫描完成后,调用回调函数来通知应用去处理
  3.  
  4. const fs = require('fs');
  5. const path = require('path');
  6.  
  7. function findLargest(dir, callback) {
  8. fs.readdir(dir, function (err, files) {
  9. if (err) return callback(err); // [1]
  10. let count = files.length; // [2]
  11. let errored = false;
  12. let stats = [];
  13. files.forEach( file => {
  14. fs.stat(path.join(dir, file), (err, stat) => {
  15. if (errored) return; // [1]
  16. if (err) {
  17. errored = true;
  18. return callback(err);
  19. }
  20. stats.push(stat); // [2]
  21.  
  22. if (--count === 0) {
  23. let largest = stats
  24. .filter(function (stat) { return stat.isFile(); })
  25. .reduce(function (prev, next) {
  26. if (prev.size > next.size) return prev;
  27. return next;
  28. });
  29. callback(null, files[stats.indexOf(largest)]);
  30. console.log('readdir finished!')
  31. }
  32. });
  33. });
  34. });
  35. console.log('before readdir callback called!')
  36. }
  37.  
  38. findLargest('./', function (err, filename) {
  39. if (err) return console.error(err);
  40. console.log('largest file was:', filename);
  41. });
  42. // 其执行log如下
  43. before readdir callback called!
  44. largest file was: halls-test.js
  45. readdir finished!

我们看看通过node --inspect-brk 调试的过程:

  1. $ node --inspect-brk maxfile.js
  2. Debugger listening on ws://127.0.0.1:9229/ed354fe8-fdfc-466b-b0ea-fcc7fccb4b36
  3. For help, see: https://nodejs.org/en/docs/inspector
  4. Debugger attached.
  5. before readdir callback called!
  6. largest file was: halls-test.js
  7. readdir finished!
  8. Waiting for the debugger to disconnect...

callback导致的问题是无法通过try catch截取错误,并且当回调嵌套时流程更加显得复杂,程序可读性差;callback将在fs.readdir的function参数中调用,该callback(本例中实际上是fs.readdir的function参数)将被fs.readdir调用操作真正异步执行完成时(本身函数调用立即返回,而执行通过系统调用异步执行),放入javascript event queue中,底层readdir实际操作(往往是由js引擎c++代码执行)结束后,将有event发生,这时会将该callback function放到event queue中(并包含了对应的readdir返回数据),从而由event loop引擎在js主线程的运行周期的适当时机来调用

2. promise

promise代表了一个异步操作最终的结果,它是一个对象,代表着延迟计算(deferred computation)的最终结果(除了延迟计算,更多的是一个异步的IO操作). promise也是一种状态机,它有三个不同的状态:pending, fulfilled,rejected.一旦promise完成(fulfilled,或者rejected),它就不能再被变更状态。

when a promise is ready, its .then/catch/finally handlers are put into the queue

当promise resolve/reject时,也就是该promise ready时,会将promise的then定义的handler插入event queue,在下一个event loop周期时,如果主线程没有任务执行了,将被取出执行

再看看以下代码对应的解读:

  1. let promise = Promise.resolve();
  2.  
  3. promise.then(() => alert("promise done"));
  4.  
  5. alert("code finished"); // this alert shows first

如果我们希望promise done的打印在code finished打印之前,怎么办?答案是then的链接,每一个then都会返回一个新的promise

  1. Promise.resolve()
  2. .then(() => alert("promise done!"))
  3. .then(() => alert("code finished"))

promise 的实现机制: https://juejin.im/post/5a30193051882503dc53af3c#heading-14

Promise.resolve schedule a microtask and the setTimeout schedule a macrotask. And the microtasks are executed before running the next macrotask

使用XMLHttpRequest实现promise形式的ajax

  1. function get(url) {
  2. // Return a new promise.
  3. return new Promise(function(resolve, reject) {
  4. // Do the usual XHR stuff
  5. var req = new XMLHttpRequest();
  6. req.open('GET', url);
  7.  
  8. req.onload = function() { // 这里是原生的callback api,也就是当onload事件发生时会被event loop调用,从而通过resolve再push到event queue中,对应then中的handler被下一个loop调用
  9. // This is called even on 404 etc
  10. // so check the status
  11. if (req.status == 200) {
  12. // Resolve the promise with the response text
  13. resolve(req.response);
  14. }
  15. else {
  16. // Otherwise reject with the status text
  17. // which will hopefully be a meaningful error
  18. reject(Error(req.statusText));
  19. }
  20. };
  21.  
  22. // Handle network errors
  23. req.onerror = function() {
  24. reject(Error("Network Error"));
  25. };
  26.  
  27. // Make the request
  28. req.send();
  29. });
  30. }

https://developers.google.com/web/fundamentals/primers/promises?hl=zh-tw

  1. get('story.json').then(function(response) {
  2. console.log("Success!", response);
  3. }, function(error) {
  4. console.error("Failed!", error);
  5. })

3. ES7 async/await关键字

  1. var sleep = function (time) {
  2. return new Promise(function (resolve, reject) {
  3. setTimeout(function () {
  4. // 返回 ‘ok’
  5. resolve('ok');
  6. }, time);
  7. })
  8. };
  9. var sleepwithReject = function (time) {
  10. return new Promise(function (resolve, reject) {
  11. setTimeout(function () {
  12. // 返回 ‘ok’
  13. reject('Error');
  14. }, time);
  15. })
  16. };
  17.  
  18. var start = async function () {
  19. let result = await sleep(3000);
  20. console.log(result); // 收到 ‘ok’
  21. };
  22. var reject = async function () {
  23. try{
  24. let result = await sleepwithReject(3000);
  25. console.log(result); // 不会执行,因为被reject了,会触发一个异常
  26. }catch (err){
  27. console.log(err);// 这里捕捉到Error
  28. }
  29. }
  30. ;
  31. start()
  32. reject()

基本规则:

1. async关键字表示这是一个async函数,await关键字只能在这个async关键字指示的函数中;

2. await表示在这里等待promise执行完成并返回结果,promise完成后才能继续执行

3. await后面跟着的应该是一个promise对象(当然如果是非promise对象,则只会立即执行)

4. await紧跟的promise resolve/reject之后其resolve或者reject返回的结果直接在这里可以synchrosely(同步地)返回

5. 如果发生错误,则可以在try catch中获取

javascript异步编程学习及实例的更多相关文章

  1. JavaScript的sleep实现--Javascript异步编程学习

    一.原始需求 最近在做百度前端技术学院的练习题,有一个练习是要求遍历一个二叉树,并且做遍历可视化即正在遍历的节点最好颜色不同 二叉树大概长这个样子: 以前序遍历为例啊, 每次访问二叉树的节点加个sle ...

  2. JavaScript异步编程

    前言 如果你有志于成为一个优秀的前端工程师,或是想要深入学习JavaScript,异步编程是必不可少的一个知识点,这也是区分初级,中级或高级前端的依据之一.如果你对异步编程没有太清晰的概念,那么我建议 ...

  3. 我了解到的JavaScript异步编程

    一. 一道面试题 前段时间面试,考察比较多的是js异步编程方面的相关知识点,如今,正好轮到自己分享技术,所以想把js异步编程学习下,做个总结. 下面这个demo 概括了大多数面试过程中遇到的问题: f ...

  4. javascript异步编程的前世今生,从onclick到await/async

    javascript与异步编程 为了避免资源管理等复杂性的问题, javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为 ...

  5. JavaScript异步编程(2)- 先驱者:jsDeferred

    JavaScript当前有众多实现异步编程的方式,最为耀眼的就是ECMAScript 6规范中的Promise对象,它来自于CommonJS小组的努力:Promise/A+规范. 研究javascri ...

  6. 5分种让你了解javascript异步编程的前世今生,从onclick到await/async

      javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是 ...

  7. 深入解析Javascript异步编程

    这里深入探讨下Javascript的异步编程技术.(P.S. 本文较长,请准备好瓜子可乐 :D) 一. Javascript异步编程简介 至少在语言级别上,Javascript是单线程的,因此异步编程 ...

  8. JavaScript 异步编程的前世今生(上)

    前言 提到 JavaScript 异步编程,很多小伙伴都很迷茫,本人花费大约一周的业余时间来对 JS 异步做一个完整的总结,和各位同学共勉共进步! 目录 part1 基础部分 什么是异步 part2 ...

  9. Javascript异步编程之一异步原理

    本系列的例子主要针对node.js环境,但浏览器端的原理应该也是类似的. 本人也是Javascript新手,把自己这段时间学习积累的要点总结下来,希望可以对同样在学习Javascript/node.j ...

随机推荐

  1. linux之shell脚本学习(一)

    #!/bin/bash echo 'hello' your_name='longxiong' echo $your_name echo ${your_name} for i in `ls /opt`; ...

  2. [KCOJ20170214]又一个背包

    题目描述 Description 小W要去军训了!由于军训基地是封闭的,小W在军训期间将无法离开军训基地.所以他没有办法出去买他最爱吃的零食.万般无奈的小W只好事先买好他爱吃的零食,装在背包里带入军训 ...

  3. Browser cannot find PAC because wpad hostname cannot be resolved

    Enterprise Network administrator may faultly forget to configure wpad hostname to DNS server. If use ...

  4. Spring Cloud微服务安全实战_2-1_开发环境

    开发环境: JDK  :1.8 IDE : idea  数据库:mysql 5.6.5 框架:springboot,mybatisplus PGA:(后边用到再安装) Promethus (普罗米修斯 ...

  5. epoll及实现http多任务(python)

    1.epoll用到了文件描述符的概念: 首先,操作系统中一切皆文件 文件与文件描述符fd 文件是应用程序与系统(包括特定硬件设备)之间的桥梁,而文件描述符就是应用程序使用这个"桥梁" ...

  6. three.js 居中-模型

    api: 代码: <!DOCTYPE html> <html lang="en"> <head> <title>three.js w ...

  7. IE和火狐的事件机制有什么区别

    1.IE的事件流是冒泡流,火狐支持冒泡流和捕获流. 2.阻止事件冒泡:IE---e.cancelBubble = true;    火狐---e.stopPropagation();

  8. 请用正则实现String.trim()

    String.prototype.trim1=function(){ return this.replace(/(^\s*)|(\s*$)/g,""); }; 写一个functio ...

  9. 剑指offer 面试题8:二叉树的下一个节点

    题目:给定一棵二叉树和其中一个节点,如何找出中序遍历序列的下一个节点?树中的节点除了有两个分别指向左.右节点的指针,还有一个节点指向父节点的指针. 中序遍历序列是{d,b,h,e,i,a,f,c,g} ...

  10. 使用Redis搭建电商秒杀系统

    背景 秒杀活动是绝大部分电商选择的低价促销.推广品牌的方式.不仅可以给平台带来用户量,还可以提高平台知名度.一个好的秒杀系统,可以提高平台系统的稳定性和公平性,获得更好的用户体验,提升平台的口碑,从而 ...