JS学习(二) 异步编程

前言

众所周知,目前主流的JS环境都是以单线程模式去执行的JavaScript代码,之所以采用单线程模式工作,与它最早的设计初衷有关.最早JS就是一门运行在浏览器端的脚本语言,目的是为了实现页面上的动态交互,而实现动态交互的核心就是DOM操作,这就决定了必须使用单线程,不然会出现很复杂的线程同步问题

同步模式

同步模式指的是代码中的任务依次执行,后一个任务必须要等待前一个任务结束才能开始执行,程序的执行顺序跟代码的编写顺序完全一致.

异步模式

不会等待这个任务的结束才开始下一个任务,对于耗时操作,都是开启过后立即往后执行下一个任务,耗时任务的后续逻辑一般通过回调函数的方式去定义
在这里插入图片描述
Promise
不多逼逼,直接上案例

function ajax (url) {
	return new Promise ((resolve, reject) => {
		let xhr = new XMLHttpRequest()
		xhr.open('GET', url)
		xhr.responseType = 'json'
		xhr.onload =function () {
			if (this.staths === 200) {
				resolve(this.response)
			}else{
				reject(new Error(this.statusText))
			}
		}
		xhr.send()
	})
}

链式调用

  • Promise 对象的 then 方法会返回一个全新的 Promise 对象
  • 后面的 then 方法就是在为上一个 then 返回的 Promise 注册回调
  • 前面 then 方法中回调函数的返回值会作为后面 then 方法回调的参数
  • 如果回调中返回的是 Promise,那后面 then 方法的回调会等待它的结束

静态方法
Promise.resolve()

  • 快速的把一个值转化为 Promise 对象;
  • 如果接收的参数是另一个 Promise 对象,那这个 Promise 对象会被原样返回
  • 如果接收的参数是一个对象,且这个对象有一个跟 Promise 对象一样的 then 方法,即 then 方法里有一个 onFulfilled 跟 onRejected 方法,那这个对象也可以作为 Promise 对象来执行.带有这个 then 方法的对象,实际上是实现了一个 thenable 的接口,即是一个可以被 then 的对象
    在这里插入图片描述
    Promise.reject()
  • 快速创建一个一定是失败的 Promise 对象

并行执行
Promise.all()

接收一个数组,数组里每个元素都是 Promise(P1) 对象,然后返回一个全新的 Promise(P2) 对象,当内部所有的 Promise(P1) 对象都完成之后,返回的 Promise(P2) 对象才会完成.此时这个 Promise(P2) 拿到的结果是个数组,数组里面包含着每个异步任务执行的结果.当且仅当所有的任务都执行成功时 Promise(P2) 才会成功结束,任何一个任务失败都会导致 Promise(P2) 失败

Promise.race()

与 all() 大致相同,不同的是 all() 会等待所有组合的 Promise 都结束而且是成功结束才会成功完成,而 race() 只会等待第一个结束的任务

执行时序

Event Loop 中,每一次循环称为 tick,每一次 tick 的任务如下:

  • 执行栈选择最先进入队列的宏任务(一般都是 script ),执行其同步代码直至结束
  • 检查是否存在微任务,有则会执行至微任务队列为空
  • 如果宿主为浏览器,可能会渲染页面
  • 开始下一轮tick,执行宏任务中的异步代码( setTimeout 等回调)

在这里插入图片描述
比较值得注意的是 Promise 既包含宏任务,也包含微任务,Promise 内部执行为宏任务,then 回调为微任务

generator

避免异步编程中回调嵌套过深,提供更好的异步编程解决方案

  • Generator(生成器):是一类特殊的函数,跟普通函数声明时的区别是加了一个*号
  • Iterator(迭代器):当我们实例化一个生成器函数之后,这个实例就是一个迭代器.可以通过 next() 方法去启动生成器以及控制生成器的是否往下执行
  • yield/next:通过 yield 语句可以在生成器函数内部暂停代码的执行使其挂起,此时生成器函数仍然是运行并且是活跃的,其内部资源都会保留下来,只不过是处在暂停状态
    在迭代器上调用 next() 方法可以使代码从暂停的位置开始继续往下执行
// 首先声明一个生成器函数
function *main() {
    console.log('starting *main()');
    yield; // 打住,不许往下走了
    console.log('continue yield 1');
    yield; // 打住,又不许往下走了
    console.log('continue yield 2');
}
// 构造处一个迭代器it
let it = main(); 

// 调用next()启动*main生成器,表示从当前位置开始运行,停在下一个yield处
it.next(); // 输出 starting *main()

// 继续往下走
it.next(); // 输出 continue yield 1

// 再继续往下走
it.next(); // 输出 continue yield 2

async&await

async & await 是 generator 的语法糖,简单来说,async 是通过 Promise 包装异步任务的

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

改成 Promise 的写法就是

new Promise((resolve, reject) => {
  async2() 
}).then(() => {
 // 执行async1()函数await之后的语句
  console.log('async1 end')
})

当调用 async1 函数时,会马上输出 async2 end,并且函数返回一个 Promise,接下来在遇到 await的时候会就让出线程开始执行 async1 外的代码(可以把 await 看成是让出线程的标志)
然后当同步代码全部执行完毕以后,就会去执行所有的异步代码,那么又会回到 await 的位置,去执行 then 中的回调

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值