当前位置: 首页 > 工具软件 > WP Async Task > 使用案例 >

3.JavaScript promise async/await & callback

方心思
2023-12-01

JavaScript是单线程的脚本语言,也就是代码是一行一行的按顺序执行。对于异步执行代码的需求ES5是使用callback函数。

console.log("start");
setTimeout(()=>{
    console.log("show after 2s");
},2000);
console.log("end")

上边代码执行结果为:

start

end

show after 2s

这是因为JS引擎会直接执行同步代码,所以会打出第一行代码的“start”,接着timeout是异步代码,会被押入栈中,JS当中的Event Loop会一直进行监听,如果主线程没有要执行的代码时会执行栈中代码,现在主线程还有代码没执行,所以先执行最后一行代码“end”。之后等待2s后,EVENT LOOP察觉到到了该执行栈中代码了,而且主线程空着,OK执行打印”show after 2S“

PS:即使延迟不是2s而是0s顺序也不会改变,因为timeout还是会押入栈中,等待主线程执行完毕再执行。

ES6针对于这种异步方案提出了新的解决方案--promises。为何引入新的方法呢?肯定是老方法--callback有弊端呗。这个弊端称之为回调地狱:

setTimeout(()=>{
    console.log("第一级回调");
    setTimeout(()=>{
        console.log("第二级回调");
        setTimeout(()=>{
        console.log("第三级回调");
            setTimeout(()=>{
                console.log("第四级回调");
                setTimeout(()=>{
                    console.log("第五级回调");
                },2000);
            },2000);
        },2000);
    },2000);
},2000);

可以看到如果下一个回调函数必须取决于上一个回调函数执行完毕,到了第五级代码就很难看懂了,这对debug来说就是个地狱。

Promises

就像金融一样,金融最重要的是信任,我信任你所以把钱借给你,而你也许诺我一段时间后把本金与利息付给我。我们的Promises也是一样,它向JS引擎许诺,在未来的某一时刻,我会告诉你执行的结果,成与不成都会告知于你。

const setTimer = (i) => {
    let promise = new Promise((resolve,reject)=>{
        try{
            setTimeout(()=>{
                console.log(`第{i}级回调`);
                resolve(i + 1);
            },2000)
        }catch(err){
            reject(err);
        }
    });
    return promise;
}

        上段代码我们将timeout这个回调函数包装成了promise,这个promise许诺JS引擎,2s后你将收到函数执行成功的消息,也就是resolve。promise在未完成时的状态为pending,当执行完resolve或reject函数后promise才变成完成状态,且resolve或reject的参数将会被传递,参数可以为任意类型。

所以回调地狱就改善成为:

setTimer(1)
    //此catch可以捕获setTimer(1)中的Exception,并继续执行接下来的promise
    //.catch(err => console.log(err);)
    .then(i=>{
        return setTimer(i);
    })
    .then(i=>{
        return setTimer(i);
    })
    .then(i=>{
        return setTimer(i);
    })
    .then(i=>{
        return setTimer(i);
    })
    //若catch放在最后,则任何exception都会中断promise链,不会继续执行发生exception后的代码
;

then方法会等到promise的状态有pending转变为完成状态后才会执行then里边的代码段,并且将promise的resolve里传递的参数获取到,例如上段代码then中的i便是resolve传递过来的。可以看到回调地狱得到妥善解决。

Async/await

怎么说呢,虽然代码有了很大改善,但总觉得代码量还是太多了:

async function print(){
    let i = 1;
    try{
        await setTimer(i++);
        await setTimer(i++);
        await setTimer(i++);
        await setTimer(i++);
        await setTimer(i++);
    }catch(err){
        console.log(err);
    }
}

如果在函数最前面加上async关键字,就表示此函数是返回Promise的,可以把此函数想象成自动new 了一个promise并返回了,在async函数里可以添加await关键字,表明要等待await后边的promise执行完毕才可以执行下一行代码,相当于之前的then语句了。

这样改动后的代码简介易读,尤其在我们做http request的时候,会用到大量的异步代码,多使用async/await同样也会是你的运行速度变快,现在的浏览器对async/await有优化。

 类似资料: