美文网首页
[es6]对异步问题的解决

[es6]对异步问题的解决

作者: 钢铁萝莉猫 | 来源:发表于2019-12-13 12:29 被阅读0次
异步问题得到解决 : 可以获取到异步操作内的数据

异步的原理:
都知道js是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,毫无疑问,这样的效率是不高的,后面的任务必须等到前面的任务执行完毕后才能执行,如果有一个比较耗时的操作,比如http请求,文件io。
其他语言遇到这种比较耗时的任务往往是开一个线程来处理,但js本身就是单线程的,js对这种任务的处理就是这个一个任务挂载起来,等耗时任务完成后再把回调函数添加到执行队列尾部。


1. 回调函数

 const f1 = (call) => {
            setTimeout(() => {
                call('123')   //两秒后输出123
            }, 2000)
        }
        f1((val) => console.log(val))
 const aa = (call) => {
            let x = 1
            setTimeout(() => {
                var y = 2
                console.log(`函数内x=${x}`)
                return call(y)
            }, 1000)

        }
        aa((arg) => {
            console.log(`回调函数内获得了y=${arg}`)
        })
        //结果:
        //函数内x=1
        //回调函数内获得了y=2

数据复杂的时候,会出现嵌套很多层的情况。有局限性。


假定有三个函数f1(),f2(),f3()。
f1执行很耗时,而 f2需要在f1执行完之后执行。

//最原始的写法-同步写法
 
f1(); //耗时很长,严重堵塞
f2(); 
f3(); //导致f3执行受到影响

为了不影响 f3的执行,我们可以把f2写成f1的回调函数。

//改进版-异步写法
function f1(callback){
  setTimeout(function () {
    // f1的任务代码
    callback();
  }, 1000);
}
 
f1(f2); //
 
f3();
  • 回调函数的本质是闭包
 function callback(val) {  //声明回调函数
            console.log(val)
        }

        function f1(callback) {  //回调函数作为参数传入f1函数
            let n = 99;
            callback(n)  //执行回调函数
        }

        f1(callback)  //获取到f1中的值n

回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,流程会很混乱,而且每个任务只能指定一个回调函数。

2. Generator

const fn = () => {
            setTimeout(() => {
                g.next('???') // {value:undefined,done:true} // 第二个yield
                // next的参数传给第一个yield
            })
        }

        function* gn() {
            let tip = yield fn()
            console.log(tip) // 输出 ???
        }

        let g = gn()
        g.next() // {value:undefined,done:false}
        // 第一个yield // 表示开始执行 generator
  • yield后面是一个包含异步操作的对象
  • generator内可以将异步写成同步
  • 第一个.next()执行第一个yield后面的内容。
  • 第二个.next()传的内容赋值给第一个yield.

.next() 括号里的内容 传值给上一个yield

【小插曲】

let ps = new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve('promise-ok') //两秒后输出 promise-ok
                }, 2000)
            })

            function* gn() {
                let res = yield ps;
                console.log(res) // 1
            }

            let g = gn()

            g.next().value.then(res => console.log(res))
            g.next(1)

            //结果
            //1
            // promise-ok

promise-ok的经历:

  • 第一个next()执行的是第一个yield → yield ps。
  • console.log(g.next()),结果是{value:undefined,done:false}。这里面的value就是ps,一个promise对象。
  • 通过.then链式调用获得resolve的内容。
  • 打印promise-ok。

3. Promise

 const p1 = new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log('第一个promise的console')
                    resolve('第一个resolve')
                }, 2000)

            })

            p1.then(res => {
                console.log(res)
                return new Promise((resolve, reject) => {
                    setTimeout(() => {
                        console.log('第二个promis的console')
                        resolve('第二个resolve')
                    }, 2000)
                })
            }).then(res => {
                console.log(res)
            })

            //结果
            // 第一个promise的console   // 两秒后
            // 第一个resolve            // 两秒后
            // 第二个promis的console    // 四秒后
            // 第二个resolve            // 四秒后

上述回调函数的改进:

          const aa = () => {
                let x = 1;
                return new Promise((res, rej) => {
                    setTimeout(() => {
                        let y = 2
                        res(y)
                    }, 1000)
                })
            }
            aa().then(res => console.log(`y=${res}`))

ajax运用promise

1.png 2.png

4. async / await

const ps = new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve('???')
                }, 2000)
            })

            async function gn() {
                let res = await ps
                console.log(res)   //  ??? 
            }

            gn()

sync函数就是Generator函数的语法糖。
async不过是把Generator函数的*号换成async,yield换成await。

async函数的优点
(1)内置执行器
Generator 函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器。也就是说,async 函数的执行,与普通函数一模一样,只要一行。
(2) 语义化更好
async 和 await,比起星号和 yield,语义更清楚了。async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
(3)更广的适用性
yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。

  • 在vue中,axios结合async/await
    3.png

部分内容来自网络,之前记录的时候忘了记下出处,欢迎有发现的好心人提出指正~

相关文章

网友评论

      本文标题:[es6]对异步问题的解决

      本文链接:https://www.haomeiwen.com/subject/shcfnctx.html