关于前端:js异步编程的三种模式

37次阅读

共计 2361 个字符,预计需要花费 6 分钟才能阅读完成。

写在后面

 javascript 语言的执行环境是 ” 单线程 ”(single thread),就是指一次只能实现一件工作。如果有多个工作,就必须排队,等后面一个工作实现,再执行前面一个工作,以此类推。
 这种模式的益处是实现起来比较简单,执行环境绝对单纯;害处是只有有一个工作耗时很长,前面的工作都必须排队等着,会迁延整个程序的执行。

单线程

function f1() {console.log('1')
}
function f2() {console.log('2')
}
f1()
f2()

 很容易能够看出,上述代码会顺次输入 1,2。因为代码是从上到下,顺次执行,执行完 f1(),才会执行 f2()。然而如果 f1()中的代码执行的是读取文件或者 ajax 操作呢,文件的读取都须要肯定工夫,难道咱们须要齐全等到文件齐全读完再进行写操作么?为了解决这个问题,接下来咱们来探索一下 js 中 同步和异步 的概念。

同步和异步

同步

  • 指在 主线程 上排队执行的工作,只有前一个工作执行结束,能力继续执行下一个工作。
  • 也就是调用一旦开始,必须这个调用 返回后果(划重点——)能力持续往后执行。程序的执行程序和工作排列程序是统一的。

异步

  • 异步工作是指不进入主线程,而进入 工作队列 的工作,只有工作队列告诉主线程,某个异步工作能够执行了,该工作才会进入主线程。
  • 每一个工作有一个或多个 回调函数。前一个工作完结后,不是执行后一个工作, 而是执行回调函数,后一个工作则是不等前一个工作完结就执行。
  • 程序的执行程序和工作的排列程序是 不统一 的,异步的。
  • 咱们罕用的 setTimeout 和 setInterval 函数,Ajax 都是异步操作。

那么如何实现异步编程呢,笔者介绍几种办法

回调函数(Callback)

回调函数,这是异步编程最根本的办法。

const fs = require('fs')
fs.readFile('./pakage.json',(err,info) => {fs.writeFile('./p.json',info,(err) => {if(!err) {setTimeout(() => {console.log('ok')
            },2000)
        }
    })
})

上述代码通过回调函数的嵌套,从文件系统中读取一个./pakage.json 文件并写入./p.json, 读取胜利两秒后输入 ’ok’。用回调来实现异步,没有什么问题。
然而试想,如果再多几个异步函数,代码整体的维护性,可读性都变的极差,如果出了 bug,修复过程也变的极为艰难,这个便是所谓的 回调函数天堂

Promise 对象

Promise 对象用于示意一个异步操作的最终状态(实现或失败),以及其返回的值。

MDN 对 Promise 定义如上,Promise 本意为 承诺,咱们能够了解为程序承诺过一段时间后会给你一个后果。
Promise 是一个对象,能够保留三个状态 每一时刻必须有一个状态。

  • 胜利 Fulfilled
  • 失败 Rejected
  • 解决中 Pending
  • 默认 pending 如果调用 resolve fulfilled
  1. 默认 pending 如果调用 reject rejeced

const fs = require('fs')
const promise1 = new Promise((resolve,reject) => {fs.readFile('./package.json',(err,info) => {resolve(info)
    })
})
const promise2 = (info) => {new Promise((resolve,reject) => {fs.writeFile('./p.json', info,(err) => {if(!err) {resolve();
            }else{reject();
            }
        })
    })
}
const promise3 = (time) => {return new Promise((resolve,reject) => {setTimeout(() => {resolve()
        },time)
    })
}
//then 链式调用
// 读文件胜利 将后果作为参数传入 promise2
promise1.then((info) => {return promise2(info)
})
.then(() => {
    // 等着后面的 promise 
    console.log('读写实现')
    return promise3(2000)
})
.then(()=> {console.log('ok')
})

 这么一看,并没有什么区别,还比下面的异步回调简单,得先新建 Promise 再定义其回调。但其实,Promise 的真正弱小之处在于它的多重链式调用,能够防止层层嵌套回调。
 咱们先应用 new 来构建一个promise。Promise 承受一个函数作为参数,该函数的两个参数别离是 resolve 和 reject。
resolve:胜利时调用,并将后果,作为参数传递进来;
reject:失败时调用,并将谬误,作为参数抛出。

  • then 办法接管两个函数作为参数,第一个参数是 Promise 执行胜利时的回调,第二个 参数是 Promise 执行失败时的回调。
  • Promise 对象的 then 办法返回一个新的 Promise 对象,因而所以能够通过 链式调用then 办法。

咱们还能够持续优化一丢丢。

参考 前端进阶面试题具体解答

async+await 语法糖

间接上代码

async function run() {
    let info = await promise1;
    await promise2(info);
    await promise3(2000);
    console.log('ok');
}

async 函数是在 ES2017 规范中引入的,使咱们异步的代码更加优雅了。这里应用 async+await 代替了.then() 办法。

  • async 必须在函数申明前
  • await 接一个 promise,那么前面的代码就会期待,等 promise resolve 了才会执行。

正文完
 0