多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[toc] # 题1、JS 中哪些代码是异步的? 答:AJAX(与服务器通信)、setTimeout、setInterval、setImmediate (node)、process.nextTick(node)。 # 题2、事件循环是怎么回事? 答:JS 把代码分为三部分:同步代码、宏任务代码、微任务代码。 执行顺序是:同步-》微任务-》宏任务。 微任务代码:node 中的 process.nextTick 等 宏任务代码:ajax、setTimeout、setInterval 等。 JS 在执行代码时分为三种任务: - 同步代码 - 异步代码 - 宏任务(macrotask): script(整体代码), AJAX、事件回调(鼠标键盘事件)、 setTimeout, setInterval, setImmediate(node独有), I/O, UI rendering - 微任务(microtask) (优先级更高) process.nextTick(node独有), Promises.then, Object.observe(废弃), MutationObserver 执行顺序: 1. 先执行同步代码 2. microtask (微任务)中的代码 3. 宏任务中的代码 ~~~ 代码演示:只能在 node 环境中执行: // 同步代码 console.log(1) // 宏任务代码 setTimeout(()=>{ console.log(2) }, 0) // 微任务代码(node环境专有) process.nextTick(()=>{ console.log(3) }) // 同步代码 console.log(4) // 输出结果: 1432 ~~~ # 题3、什么是回调地狱?如何解决? 答:在写异步代码时都需要使用回调函数,当回调的层次多时,代码不容易编写,如果出错。 解决办法:使用 ES6 中新出的 promise 以及 ES8(ES2017) 中新出 async...await 改成同步写法。 ES6 --》 ES2015 ES7 --》 ES2016 ES8 --》 ES2017 ~~~ // 代码一、传统多层嵌套回调函数(回调地狱) setTimeout(()=>{ console.log(1) setTimeout(()=>{ console.log(2) setTimeout(()=>{ console.log(3) setTimeout(()=>{ console.log(4) }, 0) }, 0) }, 0) }, 0) 代码二、把所有的异步代码封装成 Promise 对象(ES6 的 Promise 写法) // 无法是哪种方法:首先要先把异步代码封装成一个 Promise 对象: let p1 = function() { return new Promise(()=>{ // 异步代码 setTImeout(()=>{ console.log(1) },0) }) } let p2 = function() { return new Promise(()=>{ // 异步代码 setTImeout(()=>{ console.log(2) },0) }) } let p3 = function() { return new Promise(()=>{ // 异步代码 setTImeout(()=>{ console.log(3) },0) }) } let p4 = function() { return new Promise(()=>{ // 异步代码 setTImeout(()=>{ console.log(4) },0) }) } // 依次调用(避免回调地狱) p1().then(()=>{ return p2() }).then(()=>{ return p3() }).then(()={ return p4() }) 代码三、async...await (ES8出的)(以同步的方式写代码) (async function(){ await p1() await p2() await p3() await p4() })() ~~~ # 题4、什么是 Promise ?干什么用的? 答:ES6中新出的。 用途: 1. 可以用来将一段 `异步的代码` 封装成一个 Promise 对象 2. 封装完之后就可以使用 ES8 中的 async ... await 来使用同步的方式写代码了,不需要再写回调函数 # 题5、(封装 Promise简易版)如何将异步代码封装成一个没有返回值的 Promise 对象? 答: 简易版本的封装流程(没有参数、没有返回值): 1. 要定义一个函数 2. 在这个函数中创建一个 Promise 对象并返回 return new Promise 3. 把异步的代码写在 Promise 中 // 代码演示:如何将异步代码封装成 Promise 对象 ~~~ // 异步代码 setTimeout(function(){ console.log('hello') }, 0) // 把上面的异步代码封装成一个 Promise 对象 function hello() { return new Promise(function(){ setTimeout(function(){ console.log('hello') }, 0) }) } ~~~ // 代码演示:使用 Promise 对象 ~~~ // 方法一、ES6 中原始语法 hello().then(function(){ // 异步代码执行完之后的操作 }) 方法二、ES8 async ... awiat 高级语法 async function doHello() { await hello() // 执行异步 // 后续操作 } doHello() ~~~ # 题6、封装带返回值的 Promise 对象(完整)? 答: ~~~ // 模拟:一段代码的代码,这段代码返回 100 setTimeout(function(){ // 返回 100 这个数据 return 100 }, 100) // 封装带成功、失败返回值的 Promise 对象 function getData() { // 参数一、resolve,函数,成功时调用它来设置返回值 // 参数二、reject,函数,失败时调用它业设置失败的返回值 return new Promise(function(resolve, reject){ // 以下异步代码执行完之后得到 100 setTimeout(function(){ // 模拟成功 let ok = true // 判断是否成功 if(ok) { // 成功时返回 100 resolve(100) } else { // 失败时返回错误信息 reject('用户名不正确!') } }, 100) }) } // ES6 使用 getData().then(res=>{ console.log(res.data) // 100 }).catch(err=>{ console.log(err) // 用户名不正确! }) // ES8 使用 async function doData() { let data = await getData().catch(err=>{console.log(err)}) console.log(data.data) // 100 } doData() ~~~