无名杀1.10.6 async content新写法介绍
1.异步、回调函数、Promise、生成器、await & async
异步
JavaScript是单线程,那么如何实现异步?如何应对阻塞?
事实上,JavaScript分为两种模式:
同步模式
在同步模式下,浏览器会按照顺序一步一步执行。在上一行执行完毕后才会执行下一行,也就是同步程序。也就是说,同步并不是同时执行,而是排队执行。
这里有一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36// extension.js
game.import("extension", function (lib, game, ui, get, ai, _status) {
return {
name: "无名扩展", content: function (config, pack) {
}, package: {
character: {
character: {
test: ["male", "shu", 4, ['test'], []]
},
translate: {
test: '测试'
},
},
skill: {
skill: {
test: {
enable:'phaseUse',
content: function () {
console.log('content 开始执行')
player.draw()
console.log('执行摸牌')
player.loseHp()
console.log('执行失去体力')
console.log('结束')
}
}
},
translate: {
test: '测试',
test_info: '测试'
},
}
},
}
})1
2
3
4
5// console打印输出
VM1808:5 content 开始执行
VM1808:7 执行摸牌
VM1808:9 执行失去体力
VM1808:10 结束上述非常简单、容易理解。但是这种排队执行的机制,一旦中间某个任务花费时间较长,就会卡死、阻塞。
异步模式
异步模式下的代码较为跳跃(省流:菜就多练),Js线程发起一个调用,然后继续执行其他任务。此时异步线程会单独去执行这个异步任务,执行完毕后会将这个任务回调,放入消息队列排队。Js主线程在完成本轮其他任务之后,会依次执行消息队列中的任务。Js是单线程的,但是浏览器不是单线程的。
What is
Asynchronous programming(异步编程)
?异步编程技术使你的程序可以在执行一个可能长期运行的任务的同时继续对其他事件做出反应而不必等待任务完成。与此同时,你的程序也将在任务完成后显示结果。你下达一个指令,就继续执行后续代码,而不会等待它执行完毕再执行后续代码。
有意思的一点是,Js异步编程方案的曾经是回调函数
。
回调函数
What is
Callbacks(回调)
?回调函数是一个被传递到另一个函数中的会在适当的时候被调用的函数。由定义者定义,交给执行者执行。回调函数曾经是 JavaScript 中实现异步函数的主要方式。但是直接使用传统回调方式去完成复杂的异步流程,就会出现夸张的回调嵌套(回调地狱)。因此,CommonJS 社区提出了
Promise规范
。为异步编程提供一种强大规范的方案。
Promise
What is
Promise
?Promise 是现代 JavaScript 中异步编程的基础,是一个由异步函数返回的可以向我们指示当前操作所处的状态的对象。在 Promise 返回给调用者的时候,操作往往还没有完成,但 Promise 对象可以让我们操作最终完成时对其进行处理(无论Fulfilled成功还是Rejected失败)。
基本用法:
Promise是一个全局类型,可以用它来创建一个Promise实例。
来试试不用新写法,也不用step,就可以直接获取摸到的牌吧!
1 | // extension.js |
如果我们想要做更多的操作,就依然会出现回调函数嵌套的问题,Promise就没有了意义,而这种方式是错误的。应该借助于Promise then 方法链式调用
的特点,尽量保证异步任务的扁平化。
Promise 对象then方法依然会返回一个Promise对象,链式调用和this实现的并不一样,它会返回一个全新的Promise对象。如果不断的链式调用then方法,每一个then方法其实是在为上一个then方法返回的Promise对象去添加状态明确过后的回调。这些Promise会依次执行,这样就可以避免不必要的回调。若回调当中返回的不是一个Promise,而是一个普通的值,那么这个值就会被当成当前这个then方法返回的这个Promise中的值,下一个回调当中拿到的就是这个值。若没有返回任何值,那么就返回undefined。
如果在中间出现异常值(Promise调用失败),该怎么办呢?
会执行失败的回调。可以使用Promise的catch方法去注册失败的回调,这种方法也更常见一些,因为更适合链式调用。
一些常用的Promise静态方法:
- Promise.resolve() 快速将一个值转为一个Promise对象。若接收到一个Promise对象,则会原样返回。若传入一个对象,而且这个对象和Promise对象一样可以接收到成功和失败的then方法,该对象也可以作为一个Promise对象去执行,因为带有接口
- Promise.all() 当传入的所有Promise对象全部执行完毕才会执行该Promise。若任何一个失败了,就以失败结束。
- Promise.race() 可以将所有对象合并为Promise一个对象,Promise.race()只会等待第一个Promise对象结束。
Promise执行时序:
必须要等待所有的同步代码执行完毕后才会执行异步(不太严谨的说,微任务)。
Generator异步解决方案
function\*
这种声明方式 (function
关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个Generator
对象。调用一个生成器函数,并不会立即执行这个生成器函数,而会生成一个生成器对象。当我们调用生成器对象的next方法,这个生成器函数的函数体才会被执行。我们可以使用yield
关键字向外返回一个值,可以在外部拿到这个值。而yield不会像return一样结束,而是暂停这个的执行。下一次执行生成器对象的next方法时,会从yield的位置继续执行。若中间传入了参数,则作为yield的返回值。
可以使用yield关键字来暂停,以便实现更优的异步编程体验。
async & await语法糖
async 函数是使用
async
关键字声明的函数。async 函数是AsyncFunction
构造函数的实例,并且其中允许使用await
关键字。async
和await
关键字让我们可以用一种更简洁的方式写出基于Promise
的异步行为,而无需刻意地链式调用promise
。await
关键字只能出现在async函数内部。
与Generator异步方案相比,async的写法只有细微的差别。