异步解决方案有哪些?
解决方案
1.回调函数callback:
被作为实参传入另一函数,并在该外部函数内被调用,用来完成某些任务的函数。如setTimeOut
,ajax请求,readFile
等。
例:
function greeting(name){
alert('hello ' + name )
}
function processUserInput(callback){
var name = prompt('请输入你的名字')
callback(name)
}
processUserInput(greeting)
优点:
解决了异步问题
缺点:
回调地狱:多个回调函数嵌套的情况,使代码看起来很混乱,不易于维护
2.事件发布订阅
当一个任务执行完成后,会发布一个事件,当这个事件有一个或多个‘订阅者’的时候,会接收到这个事件的发布,执行相应的任务,这种模式叫发布订阅模式。如node的events,dom的事件绑定
例:
document.body.addEventListener('click',function(){
alert('订阅了')
},false)
document.body.click()
优点:
事件对象上的解耦
缺点:
消耗内存,过度适应会使代码难以维护和理解
3.Promise
Promise
是ES6提出的异步编程的一种解决方案
Promise
对象有三种状态:
pending: 初始状态,既不是成功,也不是失败状态
fulfilled: 意味着操作成功完成
rejected: 意味着操作失败
Promise
的状态只能从pending变成fulfilled,和pending变成rejected,状态一旦改变,就不会再改变,且只有异步操作的结果才能改变promise的状态。
例:
let promise = new Promise(function(resolve,reject){
fs.readFile('./1.txt','utf-8',function(err,data){
resolve(data)
})
})
promise.then(function(data){
console.log(data)
})
优点:
解决了回调地狱的问题,将异步操作以同步操作的流程表达出来
缺点:
无法取消promise。 如果不设置回调函数,Promise内部抛出的错误不会反应到外部。当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。当执行多个Promise时,一堆then看起来也很不友好。
4.Generator:
Generator是es6提出的另一种异步编程解决方案,需要在函数名之前加一个*号,函数内部使用yield语句。Generaotr函数会返回一个遍历器,可以进行遍历操作执行每个中断点yield。
例:
function * count(){
yield 1
yield 2
return 3
}
var c = count()
console.log(c.next()) // { value: 1,done: false }
console.log(c.next()) // { value: 2,done: false }
console.log(c.next()) // { value: 3,done: true }
console.log(c.next()) // { value: undefined,done: true }
优点:
没有了Promise的一堆then(),异步操作更像同步操作,代码更加清晰。
缺点:
不能自动执行异步操作,需要写多个next()方法,需要配合使用Thunk函数和Co模块才能做到自动执行。
4.Generator:
Generator是es6提出的另一种异步编程解决方案,需要在函数名之前加一个*号,函数内部使用yield语句。Generaotr函数会返回一个遍历器,可以进行遍历操作执行每个中断点yield。
例:
function * count(){
yield 1
yield 2
return 3
}
var c = count()
console.log(c.next()) // { value: 1,done: false }
console.log(c.next()) // { value: 2,done: false }
console.log(c.next()) // { value: 3,done: true }
console.log(c.next()) // { value: undefined,done: true }
优点:
没有了Promise的一堆then(),异步操作更像同步操作,代码更加清晰。
缺点:
不能自动执行异步操作,需要写多个next()方法,需要配合使用Thunk函数和Co模块才能做到自动执行。
5.async/await:
async是es2017引入的异步操作解决方案,可以理解为Generator的语法糖,async等同于Generator和co模块的封装,async 函数返回一个 Promise。
例:
async function read(){
let readA = await readFile('data/a.txt')
let readB = await readFile('data/b.txt')
let readC = await readFile('data/c.txt')
}
var c = count()
console.log(readA)
console.log(readB)
console.log(readC)
read()
优点:
内置执行器,比Generator操作更简单。async/await比*yield语义更清晰。返回值是Promise对象,可以用then指定下一步操作。代码更整洁。可以捕获同步和异步的错误。