javascript异步编程学习及实例
所谓异步就是指给定了一串函数调用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
// 遍历目录,找出最大的一个文件
// nodejs的readdir为一个典型的异步调用过程,函数调用马上返回,但是结果却等到目录扫描完成后,调用回调函数来通知应用去处理 const fs = require('fs');
const path = require('path'); function findLargest(dir, callback) {
fs.readdir(dir, function (err, files) {
if (err) return callback(err); // [1]
let count = files.length; // [2]
let errored = false;
let stats = [];
files.forEach( file => {
fs.stat(path.join(dir, file), (err, stat) => {
if (errored) return; // [1]
if (err) {
errored = true;
return callback(err);
}
stats.push(stat); // [2] if (--count === 0) {
let largest = stats
.filter(function (stat) { return stat.isFile(); })
.reduce(function (prev, next) {
if (prev.size > next.size) return prev;
return next;
});
callback(null, files[stats.indexOf(largest)]);
console.log('readdir finished!')
}
});
});
});
console.log('before readdir callback called!')
} findLargest('./', function (err, filename) {
if (err) return console.error(err);
console.log('largest file was:', filename);
});
// 其执行log如下
before readdir callback called!
largest file was: halls-test.js
readdir finished!
我们看看通过node --inspect-brk 调试的过程:
$ node --inspect-brk maxfile.js
Debugger listening on ws://127.0.0.1:9229/ed354fe8-fdfc-466b-b0ea-fcc7fccb4b36
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.
before readdir callback called!
largest file was: halls-test.js
readdir finished!
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周期时,如果主线程没有任务执行了,将被取出执行
再看看以下代码对应的解读:
let promise = Promise.resolve();
promise.then(() => alert("promise done"));
alert("code finished"); // this alert shows first

如果我们希望promise done的打印在code finished打印之前,怎么办?答案是then的链接,每一个then都会返回一个新的promise
Promise.resolve()
.then(() => alert("promise done!"))
.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
function get(url) {
// Return a new promise.
return new Promise(function(resolve, reject) {
// Do the usual XHR stuff
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function() { // 这里是原生的callback api,也就是当onload事件发生时会被event loop调用,从而通过resolve再push到event queue中,对应then中的handler被下一个loop调用
// This is called even on 404 etc
// so check the status
if (req.status == 200) {
// Resolve the promise with the response text
resolve(req.response);
}
else {
// Otherwise reject with the status text
// which will hopefully be a meaningful error
reject(Error(req.statusText));
}
};
// Handle network errors
req.onerror = function() {
reject(Error("Network Error"));
};
// Make the request
req.send();
});
}
https://developers.google.com/web/fundamentals/primers/promises?hl=zh-tw
get('story.json').then(function(response) {
console.log("Success!", response);
}, function(error) {
console.error("Failed!", error);
})
3. ES7 async/await关键字
var sleep = function (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 返回 ‘ok’
resolve('ok');
}, time);
})
};
var sleepwithReject = function (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 返回 ‘ok’
reject('Error');
}, time);
})
};
var start = async function () {
let result = await sleep(3000);
console.log(result); // 收到 ‘ok’
};
var reject = async function () {
try{
let result = await sleepwithReject(3000);
console.log(result); // 不会执行,因为被reject了,会触发一个异常
}catch (err){
console.log(err);// 这里捕捉到Error
}
}
;
start()
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异步编程学习及实例的更多相关文章
- JavaScript的sleep实现--Javascript异步编程学习
一.原始需求 最近在做百度前端技术学院的练习题,有一个练习是要求遍历一个二叉树,并且做遍历可视化即正在遍历的节点最好颜色不同 二叉树大概长这个样子: 以前序遍历为例啊, 每次访问二叉树的节点加个sle ...
- JavaScript异步编程
前言 如果你有志于成为一个优秀的前端工程师,或是想要深入学习JavaScript,异步编程是必不可少的一个知识点,这也是区分初级,中级或高级前端的依据之一.如果你对异步编程没有太清晰的概念,那么我建议 ...
- 我了解到的JavaScript异步编程
一. 一道面试题 前段时间面试,考察比较多的是js异步编程方面的相关知识点,如今,正好轮到自己分享技术,所以想把js异步编程学习下,做个总结. 下面这个demo 概括了大多数面试过程中遇到的问题: f ...
- javascript异步编程的前世今生,从onclick到await/async
javascript与异步编程 为了避免资源管理等复杂性的问题, javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为 ...
- JavaScript异步编程(2)- 先驱者:jsDeferred
JavaScript当前有众多实现异步编程的方式,最为耀眼的就是ECMAScript 6规范中的Promise对象,它来自于CommonJS小组的努力:Promise/A+规范. 研究javascri ...
- 5分种让你了解javascript异步编程的前世今生,从onclick到await/async
javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是 ...
- 深入解析Javascript异步编程
这里深入探讨下Javascript的异步编程技术.(P.S. 本文较长,请准备好瓜子可乐 :D) 一. Javascript异步编程简介 至少在语言级别上,Javascript是单线程的,因此异步编程 ...
- JavaScript 异步编程的前世今生(上)
前言 提到 JavaScript 异步编程,很多小伙伴都很迷茫,本人花费大约一周的业余时间来对 JS 异步做一个完整的总结,和各位同学共勉共进步! 目录 part1 基础部分 什么是异步 part2 ...
- Javascript异步编程之一异步原理
本系列的例子主要针对node.js环境,但浏览器端的原理应该也是类似的. 本人也是Javascript新手,把自己这段时间学习积累的要点总结下来,希望可以对同样在学习Javascript/node.j ...
随机推荐
- Alipay支付宝支付 报错 invalid [default store dir]: /tmp/
1.如果使用支付宝sdk,首先lotusphp_runtime 文件也要一起使用 支付宝现在的php sdk中有lotus框架可以和aop文件. 2.保证AopSdk.php文件中的方法可以走到这个 ...
- LOJ 2085: 洛谷 P1587: bzoj 4652: 「NOI2016」循环之美
题目传送门:LOJ #2085. 两个月之前做的傻题,还是有必要补一下博客. 题意简述: 求分子为不超过 \(n\) 的正整数,分母为不超过 \(m\) 的正整数的所有互不相等的分数中,有多少在 \( ...
- 微信小程序中的事件
事件 说明 bindtap bindload 当图片载入完毕时触发,event.detail = {height, width} bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒 ...
- HBaseAPI
环境准备 新建项目后在pom.xml中添加依赖: <dependency> <groupId>org.apache.hbase</groupId> <arti ...
- mysql之drop、truncate和delete的区别
今天在整理mysql数据库笔记的时候突然想到一个问题,就是drop.truncate和delete的区别,乍一看三者都是有删除的功能,但是具体来看还是有很多区别的.我先把这三个的作用简单说一下,有前辈 ...
- Taro-UI 2.0样式在H5上生效,微信小程序不生效?
答案: https://taro-ui.aotu.io/#/docs/questions taro-ui 自定义样式覆盖小程序组件样式使用到了 globalClass 这个微信小程序特性,由于微信小程 ...
- ESA2GJK1DH1K基础篇: 硬件使用说明
开发板板载介绍 一.示意图 1.单片机:STM32C8T6 2.Wi-Fi模块:ESP8266 3.GPRS模块:Air202 4.温湿度传感器:DHT11 5.液晶:OLED(IIC) 6.继电器 ...
- async和await对promise异步方案的改进,以及使用注意事项
async.await相比原生promise的有优势: 1.更加简洁,await一个promise即可,那么会自动返回这个promise的resolve值,无需在then函数的回调中手动取值,彻底解决 ...
- 用JQuery内置animate方法实现数字递增动画
平时使用animate只用于dom节点的动画,无意间发现JQuery内置的animate方法可实现数字动画,JQ还是挺强大的! 动画效果为从0一步步跳到84,代码如下: $({ // 起始值 coun ...
- RNN循环神经网络实现预测比特币价格过程详解
http://c.biancheng.net/view/1950.html 本节将介绍如何利用 RNN 预测未来的比特币价格. 核心思想是过去观察到的价格时间序列为未来价格提供了一个很好的预估器.给定 ...