资讯专栏INFORMATION COLUMN

JS异步那些事 一 (基础知识)

李涛 / 394人阅读

摘要:异步那些事一基础知识异步那些事二分布式事件异步那些事三异步那些事四异步那些事五异步脚本加载事件概念异步回调首先了讲讲中两个方法和定义和用法方法用于在指定的毫秒数后调用函数或计算表达式。功能在事件循环的下一次循环中调用回调函数。

JS异步那些事 一 (基础知识)
JS异步那些事 二 (分布式事件)
JS异步那些事 三 (Promise)
JS异步那些事 四(HTML 5 Web Workers)
JS异步那些事 五 (异步脚本加载)

js事件概念 异步回调:

首先了讲讲js中 两个方法 setTimeout()和 setInterval()

定义和用法:
setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。
语法:
setTimeout(callback,time)

callback 必需。要调用的函数后要执行的 JavaScript 代码串。
time 必需。在执行代码前需等待的毫秒数。

setInterval() 方法和setTimeout很相似,可按照指定的周期(以毫秒计)来调用函数或计算表达式。


比如上述代码就是可以每隔1000毫秒延迟执行timecount函数,不同的是后者是周期的执行timecount函数,
SetInterval为自动重复,setTimeout不会重复。

线程阻塞

JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序.

执行上述代码,可以发现,总的运行时间几乎要6秒多,因为是单线程,会在while循环里面消耗5秒的时间,然后才去执行settimeout函数。

队列

浏览器是基于一个事件循环的模型,在这里面,可以有多个任务队列,比如render是一个队列,响应用户输入是一个,script执行是一个。任务队列里放的是任务,同一个任务来源的任务肯定在同一个任务队列里。任务有优先级,鼠标或键盘响应事件优先级高,大概是其他任务的3倍。

而我们常用的setTimeout函数,其本质上也就是向这个任务队列添加回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线程关系,这些任务得进行排队,一个接着一个被引擎处理.

如果队列非空,引擎就从队列头取出一个任务,直到该任务处理完,即返回后引擎接着运行下一个任务,在任务没返回前队列中的其它任务是没法被执行的.

异步函数类型 异步IO:

首先来看看很典型的一个例子 ajax

异步计时:

setTimeout,setInterval都是基于事件驱动型的,通常浏览器不会给这个太快的速度,一般是200次/秒,效率太低了是吧如果遇到有密集型的运算的话,那就呵呵了。但是在node.js中还有process.nextTick()这个强大的东西,运行的速度将近10万次/秒,很可观。

process.nextTick(callback)

功能:在事件循环的下一次循环中调用 callback 回调函数。效果是将一个函数推迟到代码书写的下一个同步方法执行完毕时或异步方法的事件回调函数开始执行时;与setTimeout(fn, 0) 函数的功能类似,但它的效率高多了。

基于node.js的事件循环分析,每一次循环就是一次tick,每一次tick时,v8引擎从事件队列中取出所有事件依次进行处理,如果遇到nextTick事件,则将其加入到事件队尾,等待下一次tick到来时执行;造成的结果是,nextTick事件被延迟执行;

nextTick的确是把某任务放在队列的最后(array.push)
nodejs在执行任务时,会一次性把队列中所有任务都拿出来,依次执行
如果全部顺利完成,则删除刚才取出的所有任务,等待下一次执行
如果中途出错,则删除已经完成的任务和出错的任务,等待下次执行
如果第一个就出错,则throw error

下面看一下应用场景(包含计算密集型操作,将其进行递归处理,而不阻塞进程):

var http = require("http");
var wait = function (mils) {
    var now = new Date;
    while (new Date - now <= mils);
};
function compute() {
    // performs complicated calculations continuously
    console.log("start computing");
    wait(1000);
    console.log("working for 1s, nexttick");
    process.nextTick(compute);
}
http.createServer(function (req, res) {
    console.log("new request");
    res.writeHead(200, {"Content-Type": "text/plain"});
    res.end("Hello World");
}).listen(5000, "127.0.0.1");
compute();
异步错误处理 异步异常的特点

由于js的回调异步特性,无法通过try catch来捕捉所有的异常:

try {
  process.nextTick(function () {
      foo.bar();
  });
} catch (err) {
  //can not catch it
}

而对于web服务而言,其实是非常希望这样的:

//express风格的路由
app.get("/index", function (req, res) {
  try {
    //业务逻辑
  } catch (err) {
    logger.error(err);
    res.statusCode = 500;
    return res.json({success: false, message: "服务器异常"});
  }
});

如果try catch能够捕获所有的异常,这样我们可以在代码出现一些非预期的错误时,能够记录下错误的同时,友好的给调用者返回一个500错误。可惜,try catch无法捕获异步中的异常。
难道我们就这样放弃了么? 其实还有一个办法

onerror事件

我们一般通过函数名传递的方式(引用的方式)将要执行的操作函数传递给onerror事件,如

window.onerror=reportError;
window.onerror=function(){alert("error")}

但我们可能不知道该事件触发时还带有三个默认的参数,他们分别是错误信息,错误页面的url和错误行号。

 
嵌套式回调的解嵌套

JavaScript中最常见的反模式做法是,回调内部再嵌套回调。

 

这里定义了一个异步函数checkPassword,它触发了另一个异步函数db.query,而后者又可能触发另外一个异步函数hash。它能用,而且简洁明了。但是,如果试图向其添加新特性,它就会变得毛里毛躁、险象环生,比如去处理那个数据库错误,而不是抛出错误、记录尝试访问数据库的次数、阻塞访问数据库,等等。
下面我们换一种写法,虽然这种写法很啰嗦但是可读性更高而且更易扩展。

 

在平时写嵌套时,我们应该尽量避免多层嵌套,不然中间某个地方出错了将会导致你投入更多的时间去debug。

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

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

相关文章

  • JS异步那些 四(HTML 5 Web Workers)

    摘要:向添加一个事件监听器当传递消息时,会执行事件监听器中的代码。终止当我们创建对象后,它会继续监听消息即使在外部脚本完成之后直到其被终止为止。 JS异步那些事 一 (基础知识)JS异步那些事 二 (分布式事件)JS异步那些事 三 (Promise)JS异步那些事 四(HTML 5 Web Workers)JS异步那些事 五 (异步脚本加载) 什么是 Web Worker? 当在 HTML ...

    ZoomQuiet 评论0 收藏0
  • JS异步那些 三 (Promise)

    摘要:异常处理异常处理一直是回调的难题,而提供了非常方便的方法在一次调用中,任何的环节发生,都可以在最终的中捕获到错误处理基本的小结具体的很多的用法可以参考阮一峰的入门教程,还有就是上面提到的电子书。 JS异步那些事 一 (基础知识)JS异步那些事 二 (分布式事件)JS异步那些事 三 (Promise)JS异步那些事 四(HTML 5 Web Workers)JS异步那些事 五 (异步脚本...

    wenzi 评论0 收藏0
  • JS异步那些 五 (异步脚本加载)

    摘要:遵循的是异步模块定义规范,遵循的是通用模块定义规范。不同的脚本加载这个模块,得到的都是同一个实例。关于异步那些事就写到这里了,很多地方理解的不够深刻希望大家多多指教。 JS异步那些事 一 (基础知识)JS异步那些事 二 (分布式事件)JS异步那些事 三 (Promise)JS异步那些事 四(HTML 5 Web Workers)JS异步那些事 五 (异步脚本加载) 异步脚本加载 阻塞性...

    terasum 评论0 收藏0
  • 2018 浅谈前端面试那些

    摘要:声明的变量不得改变值,这意味着,一旦声明变量,就必须立即初始化,不能留到以后赋值。 虽然今年没有换工作的打算 但为了跟上时代的脚步 还是忍不住整理了一份最新前端知识点 知识点汇总 1.HTML HTML5新特性,语义化浏览器的标准模式和怪异模式xhtml和html的区别使用data-的好处meta标签canvasHTML废弃的标签IE6 bug,和一些定位写法css js放置位置和原因...

    LiuRhoRamen 评论0 收藏0

发表评论

0条评论

李涛

|高级讲师

TA的文章

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