• 异步调用在JavaScript中的执行过程及期原理:

    异步调用示例.png


    • 调用栈 Call stack,是正在执行的工作表

    • 消息队列 Queue,就是待办的工作表

    • setTimeout是异步调用,Web APIs会为它执行其内部api的动作

    • 同步或异步:运行环境提供的API是以同步还是异步模式的方式工作

    • 同步模式API:当前任务执行完,才会往下执行,比如console.log

    • 异步模式API:下达任务开启的指令,就会继续往下执行,代码不会在这一行等待结束,比如setTimeout

    • 回调函数,放在函数当中,异步任务完成即会调用,想要做的事情

    • Promise

      • Promise 对象的then方法会返回一个全新的Promise对象

      • 后面的then方法就是在为上一个then返回的Promise注册回调

      • 前面then方法中回调函数的返回值会作为后面then方法回调的参数

      • 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束 ```javascript // Promise 方式的 AJAX function ajax (url) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest() xhr.open(‘GET’, url) xhr.responseType = ‘json’ xhr.onload = function () { if (this.status === 200) {
        1. resolve(this.response)
        } else {
        1. reject(new Error(this.statusText))
        } } xhr.send() }) }

    //ajax(‘/api/users11.json’) //.then(function onFulfilled (value) { // console.log(‘onFulfilled’, value) //}, function onRejected (error) { // console.log(‘onRejected’, error) //})

    //使用 catch 注册失败回调是更常见的

    ajax(‘/api/users11.json’) .then(function onFulfilled (value) { console.log(‘onFulfilled’, value) }) .catch(function onRejected (error) { console.log(‘onRejected’, error) })

    1. - <br />Promise 并行执行
    2. - <br />Promise.all()
    3. - <br />多个请求,同时调用,全部返回结果,才结束
    4. ```javascript
    5. ajax('/api/urls.json')
    6. .then(value => {
    7. const urls = Object.values(value)
    8. const tasks = urls.map(url => ajax(url))
    9. return Promise.all(tasks)
    10. })
    11. .then(values => {
    12. console.log(values)
    13. })
    1. - Promise.race()
    2. - 也能合并执行,但是只会等待第一个任务结束,就会完成Promise对象

    • Promise的回调会作为微任务执行,会在本轮调用结束的末尾自动执行

    • setTimeout是宏任务,在队伍末尾

    • 目前绝大多数异步调用都是作为宏任务执行

    • Promise MutationBoserver process.nextTick 是微任务

    • Generator 生成器函数 ```javascript // 生成器函数回顾 function * foo () { console.log(‘start’)

      try {

      1. const res = yield 'foo'
      2. console.log(res)

      } catch (e) {

      1. console.log(e)

      } } //此处得到一个生成器对象 const generator = foo()

    const result = generator.next() //这里next()会一直执行到上面yield关键词的位置,把yield后面这个值,返回出去 //然后foo函数暂停下来,值用为foo的value返回,同时生成器里有一个done属性,表示是否完成构造函数 console.log(result) //所以此处打印: { value: “foo” , done: false}

    // generator.next(‘bar’) //这里再一次调用next的话,就会从yield往下执行到结束,或者到下一个yield的位置

    generator.throw(new Error(‘Generator error’)) //throw方法也会让生成器函数继续往下执行,但会抛出一个异常 // Error: Generator error

    1. - generator 异步方案
    2. ```javascript
    3. // Generator 配合 Promise 的异步方案
    4. function ajax (url) {
    5. return new Promise((resolve, reject) => {
    6. var xhr = new XMLHttpRequest()
    7. xhr.open('GET', url)
    8. xhr.responseType = 'json'
    9. xhr.onload = () => {
    10. if (xhr.status === 200) {
    11. resolve(xhr.response)
    12. } else {
    13. reject(new Error(xhr.statusText))
    14. }
    15. }
    16. xhr.send()
    17. })
    18. }
    19. function * main () {
    20. try {
    21. const users = yield ajax('/api/users.json')
    22. console.log(users)
    23. const posts = yield ajax('/api/posts.json')
    24. console.log(posts)
    25. const urls = yield ajax('/api/urls11.json')
    26. console.log(urls)
    27. } catch (e) {
    28. console.log(e)
    29. }
    30. }
    31. const g = main()
    32. const result = g.next()
    33. //这里value就会是第一个yield位置返回的值,然后通过then的方式去指定Promise的回调
    34. result.value.then(data => {
    35. //第一个拿到的结果作为参数传给g,继续执行,
    36. const result2 = g.next(data)
    37. //这样就近乎于避免了promise的回调,有一种同步代码的体验
    38. if (result2.done) return
    39. //如果有第二个请求就按第一个一样调用.then方法
    40. result2.value.then(data => {
    41. const result3 = g.next(data)
    42. if (result3.done) return
    43. //当done为true时,就会结束
    44. result3.value.then(data => {
    45. g.next(data)
    46. })
    47. })
    48. })
    49. //用递归优化
    50. function handleResult (result) {
    51. if (result.done) return // 生成器函数结束
    52. result.value.then(data => {
    53. handleResult(g.next(data))
    54. }, error => {
    55. g.throw(error)
    56. })
    57. }
    58. handleResult(g.next())
    59. //执行器函数
    60. <!-- function co (generator) {
    61. const g = generator()
    62. function handleResult (result) {
    63. if (result.done) return // 生成器函数结束
    64. result.value.then(data => {
    65. handleResult(g.next(data))
    66. }, error => {
    67. g.throw(error)
    68. })
    69. }
    70. handleResult(g.next())
    71. }
    72. co(main) -->
    73. //这是在async await 出来之前最常用的异步方案
    • async await

      • 语言层面的异步编程标准 ```javascript //上面简化 // await关键词,只能出现在async函数内部 async function main () { try { const users = await ajax(‘/api/users.json’) console.log(users)

        const posts = await ajax(‘/api/posts.json’) console.log(posts)

        const urls = await ajax(‘/api/urls.json’) console.log(urls) } catch (e) { console.log(e) } } //不需要co生成器了 //main ()

    //还可以返回一个promise对象,以便于对整体代码进行控制 const promise = main()

    promise.then(() => { console.log(‘all completed’) }) ```