一、为什么JavaScript是单线程?
JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
一种是同步任务(synchronous),另一种是异步任务(asynchronous)。
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
-------------------------------------------------------------------------
js的异步操作的几种方法:
1.回调函数
function fn1 () {
console.log('方法一')
} function fn2 () {
setTimeout(() => {
console.log('方法二')
}, 1000)
} function fn3 () {
console.log('方法三')
} 现在我希望可以依次执行fn1,fn2,fn3。为了保证fn3在最后执行,我们可以把它作为fn2的回调函数:
function fn2 (f) {
setTimeout(() => {
console.log('方法二')
f()
}, 1000)
} fn2(fn3)
由此可以看出fn2和fn3完全耦合在一起,如果多了就耦合度很高;
-----------------------------------------------------------------------------
2.事件发布/订阅(可以在es5下相当优雅地处理异步操作)
fn1,fn2,fn3都可以视作一个事件的发布者,只要执行它,就会发布一个事件。这个时候,我们可以通过一个事件的订阅者去批量订阅并处理这些事件,包括它们的先后顺序。
class AsyncFunArr {
constructor (...arr) {
this.funcArr = [...arr]
} next () {
const fn = this.funcArr.shift()
if (typeof fn === 'function') fn()
} run () {
this.next()
}
} const asyncFunArr = new AsyncFunArr(fn1, fn2, fn3)
然后在fn1,fn2,fn3内调用其next()方法;
function fn1 () {
console.log('方法一')
asyncFunArr.next()
} function fn2 () {
setTimeout(() => {
console.log('方法二')
asyncFunArr.next()
}, 500)
} function fn3 () {
console.log('方法三')
asyncFunArr.next()
} //依次输出方法一、方法二、方法三
---------------------------------------------------------------------------------
3.Promise
function fn1 () {
console.log('方法一')
} function fn2 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('方法二')
resolve()
}, 500)
})
} function fn3 () {
console.log('方法三')
} 其中fn2是一个返回Promise的异步函数,现在按顺序执行它们; fn1()
fn2().then(() => { fn3() }) //依次输出方法一、方法二、方法三
---------------------------------------------------------------------------------
4.generator(这种方式还是不够优雅)
function fn1 () {
console.log('方法一')
} function fn2 () {
setTimeout(() => {
console.log('方法二')
af.next()
}, 500)
} function fn3 () {
console.log('方法三')
} function* asyncFunArr (...fn) {
fn[0]()
yield fn[1]()
fn[2]()
} const af = asyncFunArr(fn1, fn2, fn3) af.next() //依次输出方法一、方法二、方法三 如果有多个异步函数,那么这个generator函数肯定得改写,而且在语义化的程度来说也有一点不太直观。
------------------------------------------------------------------------------------
5.优雅的async/await(最新版本的Node已经可以原生支持async/await写法了,通过各种pollyfill也能在旧的浏览器使用。)
function fn1 () {
console.log('方法一')
} function fn2 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('方法二')
resolve()
}, 500)
})
} function fn3 () {
console.log('方法三')
} async function asyncFunArr () {
fn1()
await fn2()
fn3()
} asyncFunArr() //依次输出方法一、方法二、方法三 异步的操作都返回Promise,需要顺序执行时只需要await相应的函数即可,这种方式在语义化方面非常友好;

js单线程和js异步操作的几种方法的更多相关文章

  1. 从浏览器多进程到JS单线程,JS运行机制的一次系统梳理

    前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正. ----------超长文+多图预警,需要花费不少时间.---------- 如果看完本文后,还对进程线程傻傻分不清,不清楚浏 ...

  2. 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理

    前言 来源:https://dailc.github.io/2018/01/21/js_singlethread_eventloop.html 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会 ...

  3. 原生JS—实现图片循环切换的两种方法

    今天我们主要讲讲如何使用原生JS实现图片的循环切换的方法.多余的话我们就不多说了,我们一个一个开始讲吧. 1  原生JS实现图片循环切换 -- 方法一 在上栗子之前我们先简单介绍一下所用的一些知识点. ...

  4. JavaScript进阶(四)js字符串转换成数字的三种方法

    js字符串转换成数字的三种方法 在js读取文本框或者其它表单数据的时候获得的值是字符串类型的,例如两个文本框a和b,如果获得a的value值为11,b的value值为9 ,那么a.value要小于b. ...

  5. js 控制页面跳转的5种方法

    js 控制页面跳转的5种方法 编程式导航: 点击跳转路由,称编程式导航,用js编写代码跳转. History是bom中的 History.back是回退一页 Histiory.go(1)前进一页 Hi ...

  6. Jsp页面跳转和js控制页面跳转的几种方法

    Jsp 页面跳转的几种方法 1. RequestDispatcher.forward() 在服务器端起作用,当使用forward()时,Servlet engine传递HTTP请求从当前的Servle ...

  7. js 动态加载事件的几种方法总结

    本篇文章主要是对js 动态加载事件的几种方法进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助   有些时候需要动态加载javascript事件的一些方法往往我们需要在 JS 中动态添 ...

  8. js如何动态创建表格(两种方法)

    js如何动态创建表格(两种方法) 一.总结 一句话总结: 1.方法一:写好创建表格的html代码,将之赋值给div的innerHTML. 2.方法二.直接用创建好的table元素的方法insertRo ...

  9. js中常用追加元素的几种方法

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

随机推荐

  1. windows下关闭指定端口服务,解决tomcat端口占用问题

    http://blog.aizhet.com/Server/640.html 在windows下做java EE的开发时:搭建 Eclipse+tomcat的java web开发环境:在应用之中经常遇 ...

  2. QTextEdit/QPlainTextEdit添加文字超出视图后,滚动条自动移至最底部

    void ThreadExit::onTaskPerformState(const QString& strStatus) { //追加文本(ui.taskStatusTextEdit是一个Q ...

  3. SPOJ:Another Version of Inversion(二维数组的逆序对)

    DCE Coders admins are way much geekier than they actually seem! Kartik has been following that tradi ...

  4. MyBatis学习 之 三、SQL语句映射文件(2)增删改查、参数、缓存

    2.2 select 一个select 元素非常简单.例如: <!-- 查询学生,根据id --> <select id="getStudent" paramet ...

  5. Prime Cryptarithm

    链接 分析:对于三位数我们限定为[100,999],两位数我们限定为[10,99],然后我们依次判断是否满足乘法式且各个数位是否在数列中,若都满足+1 /* PROB:crypt1 ID:wangha ...

  6. Brackets(区间dp)

    Brackets Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8017   Accepted: 4257 Descript ...

  7. angularJS ng-bind用法

    ng-bind 指令绑定控制器函数 函数名() 到 标签里面 ; ng-bind是从$scope -> view的单向绑定ng-modle是$scope <-> view的双向绑定; ...

  8. AJAX --- 一种创建交互式网页应用的网页开发技术

    目录 AJAX 创建XHR实例 指定readyStatechange事件处理程序 启动请求 发送请求 接收数据 取消XHR请求/响应 AJAX ajax核心技术就是 XMLHttpRequest 对象 ...

  9. 推荐几本javascript与jquery的好书

    有人说只要了解了javascript的基本语法,就可以通过看别人的代码来学习javascript了,我不敢苟同.代码是死的,它很难让你有自己的想法,而一本好书如果结构清晰,各个章节都立意明确循序渐进( ...

  10. PostgreSQL新手教程

    自从MySQL被Oracle收购以后,PostgreSQL逐渐成为开源关系型数据库的首选. 本文介绍PostgreSQL的安装和基本用法,供初次使用者上手.以下内容基于Debian操作系统,其他操作系 ...