回调函数的理解-Callback,Promise,Async Await(JS学习笔记)

466 阅读3分钟

1.什么时候需要回调函数?

什么时候需要使用回调函数?比如在JavaScript中,我们需要向服务端request一个请求,这可能花费几秒钟来等待数据返回,我们没有必要硬等数据,而可以先干别的事,这时候回调函数(Callbacks)就可以派上用场了。下面通过一个和服务器或数据库交互的例子展现他们的使用:

const posts = [
    {title: 'Post One', body: 'This is post one'},
    {title: 'Post Two', body: 'This is post two'}
]

function getPosts() {
    setTimeout(()=>{
        let output = ''
        posts.forEach((post, index)=>{
            output += `<li>${post.title}</li>`
        })
        document.body.innerHTML = output
    },1000)
}

setTimeout(()=>{},1000)是一个基本的回调函数,它可以让我们在1秒之后再执行所需的函数(注意:表示模板语法需要使用反括号,所以在forEach循环中我们需要使用反括号``)。
执行这个函数,我们会发现posts数组中的两条数据在1秒之后成功显示。

getPosts()

因为我们需要和服务器交互,所以需要有添加功能。于是接着创建一个添加函数,这次我们设置为2秒的setTimeout()。

function createPost(post){
    setTime(() => {
        post.push(post)
    },2000)
}

createPost({title:'Post Three', body: 'This is post three'})//函数调用形式

2.Callbacks

我们在createPost()中添加一个callback参数,这个参数你想叫什么都可以,为了方便表示直接设置为'callback'。

function createPost(post, callback){
    setTimeout(() => {
        posts.push(post)
        callback()
    },2000)
}

这个callback参数的作用就是紧接着post.push之后要干的事,于是我们把上面定义的getPosts传入createPost中:

createPost({title:'Post Three', body: 'This is post three'},getPosts)

在浏览器执行createPost,你会发现三个数据都被添加进去,并且一同被显示了出来。他的执行逻辑是首先等待2秒之后执行posts.push(post),之后等待1秒执行getPosts(),这样你就对回调函数有了一个基本理解。

3.Promise

Promise是为了解决回调地狱而在ES6新增的函数,在英语里promise的意思是约定,我们可以形象理解为答应了朋友要干一件事就是promise。Promise有resolve,reject两种状态。见名知意,resolve代表Promise成功解决,reject代表发生了一些错误导致失约了。
下面我们把createPost函数从Callback形式改成Promise形式,把它从“地狱”中拉回来。

function createPost(post){
    return new Promise(
        (resolve, reject) => {
            setTimeout(() => {
                posts.push(post)
                
                const error = false
                
                if (!error) {
                    resolve()
                } else {
                    reject('Error: Something went wrong')
                }
            },2000)
        }
    )
}

之后就是调用函数了,在Promise中使用Promise.then()方法来回调:

createPost({title:'Post Three', body: 'This is post three'})
    .then(getPosts)

我们后续想要写更多的回调函数,只需要在.then()方法后面继续加.then()就行:

createPost({title:'Post Three', body: 'This is post three'})
    .then(getPosts)
    .then(XXX)
    .then(YYY)
    .then(...)

3.Async Await

在ES7中新增了Async,Await,它的意义是使我们能更加方便的用Promise。

继续我们的例子,我们不对Promise版的createPost进行修改,还是继续沿用:

function createPost(post){
    return new Promise(
        (resolve, reject) => {
            setTimeout(() => {
                posts.push(post)
                
                const error = false
                
                if (!error) {
                    resolve()
                } else {
                    reject('Error: Something went wrong')
                }
            },2000)
        }
    )
}

接着使用Async,Await新建一个init函数,这个函数声明前加上async,在init函数内需要被等待的函数前加上await,意思就变成了先等createPost执行完毕,然后执行getPosts:

async function init() {
    await createPost({title:'Post Three', body: 'This is post three'})
    
    getPosts()
}

init是封装好的函数,我们还要调用它:

init()

Promise还有一些具体方法,再学习一段时间继续总结。