IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> JS异步编程 -> 正文阅读

[JavaScript知识库]JS异步编程

同步与异步

同步:程序代码一行一行的执行,只有上一行的代码执行完成才能继续执行下一行代码。
异步:不用等到上一行代码执行再执行下一行代码。比如程序里有一个2s的定时器,JS是一个单线程的运行机制,他不会在这干等2s,而是去执行其他事件。这就是JS异步高效性。

事件循环机制

JS运行机制里会有一个主线程,宏任务队列,微任务队列。
事件循环机制:

  1. 将同步宏任务(打印、promise里回调函数…)加入主线程中
  2. 执行完主线程中的任务,将微任务队列加入主线程中
  3. 再次执行主线程中的任务(异步微任务),执行完将宏任务队列加入主线程中
  4. 再次执行主线程中的任务(异步宏任务),执行完跳到第2步,不断重复

异步宏任务:setTimeout、setInterval…
异步微任务:promise.then()

总结:事件循环机制为:同步宏任务 -> 异步微任务 -> 异步宏任务 -> 异步微任务 -> 异步宏任务 ->…

回调地狱

回调地狱:例如接口A需要接口B的回调res数据去请求数据,如果嵌套多层,就会产生回调地狱。

setTimeout(() => {
    console.log('1')
    setTimeout(() => {
        console.log('2')
        setTimeout(() => {
            console.log('3')
            console.log('...')
        }, 1000)
    }, 1000)
}, 1000)

这样写即显得可读性不好,又显得维护性不好。就这样,出现了ES6里的Promise来解决回调地狱问题。

Promise

Promise的三种状态:pending(未确认)、fulfilled(成功)、rejected(失败)。
Promise的状态改变只能从:pending -> fulfilled 或者是 pending -> rejected。

let p = new Promise((resolve, reject) => {
    console.log(222);   // 会直接执行
    resolve(1)

})
p.then((res) => {
    setTimeout(() => {
        console.log(res)
    }, 1000);
    return res + 1
}).then((res) => {
    setTimeout(() => {
        console.log(res)
    }, 2000);
    return res + 1
}).then((res) => {
    setTimeout(() => {
        console.log(res)
    }, 3000);
    
})

创建Promise对象,里面接收一个resolve和reject两个参数的回调函数,分别代表成功和失败状态。在定义的同时会直接执行回调函数里的代码,然后使用.then的方式获取resolve的参数,使用.catch获取reject里的参数。执行完.then或者是.catch会返回一个Promise对象,就可以继续.then了。这样不仅解决了回调地狱的问题,还显得代码可读性好,易于维护。但是,Promise当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成),而且它一旦创建了,就无法取消了。后来就出现了Generator。

Generator

Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态,但是只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();

// 运行结果:
hw.next()// { value: 'hello', done: false }
hw.next()// { value: 'world', done: false }
hw.next()// { value: 'ending', done: true }
hw.next()// { value: undefined, done: true }

由结果可以看出,Generator函数被调用时并不会执行,只有当调用next方法、内部指针指向该语句时才会执行,即函数可以暂停,也可以恢复执行。每次调用遍历器对象的next方法,就会返回一个有着valuedone两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。

Generator 函数暂停恢复执行原理:使用协程的思想( 一个线程(或函数)执行到一半,可以暂停执行,将执行权交给另一个线程(或函数),等到稍后收回执行权的时候,再恢复执行。这种可以并行执行、交换执行权的线程(或函数),就称为协程。 )。

Async/Await

async 是Generator函数的语法糖 。 async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await 。
返回值是 Promise。 async 函数返回值是 Promise 对象,比 Generator 函数返回的 Iterator 对象方便,可以直接使用 then() 方法进行调用。
分析下面两道题:

console.log('script start')

async function async1() {
	await async2()
	console.log('async1 end')
}
async function async2() {
	console.log('async2 end')
}
async1()

setTimeout(function() {
	console.log('setTimeout')
}, 0)

new Promise(resolve => {
	console.log('Promise')
	resolve()
})
.then(function() {
	console.log('promise1')
})
.then(function() {
	console.log('promise2')
})

console.log('script end')
// script start => async2 end => Promise => script end => async1 end => promise1 => promise2 => setTimeout
console.log('script start')

async function async1() {
	await async2()
	console.log('async1 end')
}
async function async2() {
	console.log('async2 end')
	return Promise.resolve().then(()=>{
 		console.log('async2 end1')
})
}
async1()

setTimeout(function() {
	console.log('setTimeout')
}, 0)

new Promise(resolve => {
	console.log('Promise')
	resolve()
})
.then(function() {
	console.log('promise1')
})
.then(function() {
	console.log('promise2')
})

console.log('script end')
// script start => async2 end => Promise => script end =>async2 end1 => promise1 => promise2 => async1 end => setTimeout

async函数返回的是一个promise对象,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。await相当于Promise的then。

await后面的函数会先执行一遍,然后就会跳出整个async函数来执行后面js栈的代码。等本轮事件循环执行完了之后又会跳回到async函数中等待await。后面表达式的返回值,如果返回值为非promise则继续执行async函数后面的代码,否则将返回的promise放入微任务队列。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章           查看所有文章
加:2022-04-06 23:09:19  更:2022-04-06 23:09:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:15:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码