js 異步問題

異步的概念

js的異步的概念的起因?yàn)閖s是單線程語言,一次只能同時(shí)做一件事。js和dom渲染公用同一個(gè)線程,因?yàn)閖s可修改dom結(jié)構(gòu),dom渲染的時(shí)候,js必須停止,js運(yùn)行時(shí),dom停止渲染。
異步是由js單線程這個(gè)原因而來的,并不是故意搞一個(gè)來為難大家,異步的存在是解決js運(yùn)行機(jī)制的問題的。
所以我們遇到等待(網(wǎng)絡(luò)請(qǐng)求,定時(shí)任務(wù))時(shí)不能卡住,需要用異步(回調(diào)callback形式)解決。

異步和同步的區(qū)別:

同步

console.log(100);
alert(200);
console.log(300);

一個(gè)hin簡(jiǎn)單的例子,一個(gè)console打印100,接著一個(gè)alert彈出,這時(shí)下一個(gè)console是不會(huì)執(zhí)行的,如果你不點(diǎn)擊alert,那么這么地方就卡住了,后面的東西都不會(huì)執(zhí)行,瀏覽器也不會(huì)渲染。只有當(dāng)你點(diǎn)擊alert彈框的確定后,才會(huì)console打印300,這就是同步。
同步簡(jiǎn)單來說,就是一個(gè)事件的開始必須等待上一個(gè)事件的結(jié)束。同步會(huì)阻塞代碼執(zhí)行。

異步

console.log(100);
setTimeout(function() {
    console.log(200)
}, 1000);
console.log(300);

又一個(gè)hin簡(jiǎn)單的例子,一個(gè)console打印100,接著是一個(gè)setTimeout定時(shí)器,1秒后執(zhí)行console打印200,那么等待這1秒就卡這兒?jiǎn)???dāng)然不行了,要繼續(xù)執(zhí)行下面的console打印300才行,然后1秒后再打印定時(shí)器內(nèi)的200。
異步就是為了解決同步的問題才誕生的,如果代碼中都是像同步的例子那樣,那樣體驗(yàn)就太差了。
每一個(gè)異步函數(shù)就是一個(gè)callback回調(diào)函數(shù)。異步不會(huì)阻塞代碼執(zhí)行。

?

異步的應(yīng)用場(chǎng)景

對(duì)于前端來說,最主要的兩個(gè)場(chǎng)景就是:

  • 網(wǎng)絡(luò)請(qǐng)求(如ajax圖片加載)
  • 定時(shí)任務(wù)(如setTimeout)
    ?
console.log('start');
$.get('./data.json', function() {
    console.log(data1);
});
console.log('end');

這是一個(gè)jq ajax網(wǎng)絡(luò)請(qǐng)求的例子,這個(gè)網(wǎng)絡(luò)請(qǐng)求我們調(diào)用就行了,愛什么時(shí)候返回就什么時(shí)候返回,反正不影響后面的console就行。
?

console.log('start');
let img = document.createElement('img');
img.onload = function() {
    console.log('loaded');
}
img.src = '/xxx.png';
console.log('end');

這是一個(gè)圖片加載的例子,這個(gè)onload也是callback函數(shù),圖片先讓它加載著,不用管它,不影響后面的console輸出end就好。
?

console.log(100);
setTimeout(function() {
    console.log(200)
}, 1000);
console.log(300);

// --------------------

console.log(100);
setInterval(function() {
    console.log(200)
}, 1000);
console.log(300);

setTimeoutsetInterval,就不多說了。
?

異步的大坑 - callbak hell

什么是callback hell? callback hell就是 回調(diào)地獄。
場(chǎng)景:我們一般在寫代碼的時(shí)候,有時(shí)候B接口需要用到A接口返回的數(shù)據(jù),C接口需要用到B接口返回的數(shù)據(jù),這樣就會(huì)寫成三四個(gè)回調(diào)函數(shù)嵌套。這樣寫代碼,其實(shí)沒有問題。但是你沒有想過,如果是8,9個(gè)接口嵌套,是不是就原地爆炸???
像這樣:

// 獲取第一份數(shù)據(jù)
$.get(url1, (data1) => {
    console.log(data1);
    // 獲取第二份數(shù)據(jù)
    $.get(url2, (data2) => {
        console.log(data2);
        // 獲取第三份數(shù)據(jù)
        $.get(url3, (data3) => {
             console.log(data3);
             // 還可能獲取更多的數(shù)據(jù)
        })
    })
})

于是,為了解決這個(gè)問題,promise誕生了。

Promise

上面的代碼,我們用promise實(shí)現(xiàn)是醬的:

// 先用promise封裝一下ajax請(qǐng)求
function getData(url) {
    return new Promise((resolve, reject) => {
        $.ajax({
            url,
            success(data) {
                resolve(data);
            }
            error(err) {
                reject(err);
            }
        })
    })
}

// 實(shí)現(xiàn)
getData(url1).then((data1) => {
    console.log(data1);
    return getData(url2);
}).then(data2 => {
    console.log(data2);
    return getData(url3);
}).then(data3 => {
    console.log(data3);
}).catch(err => console.log(err));

promise解決的問題其實(shí)還是用了callback的形式,只不過把callback形式變成了一個(gè)非嵌套的形式,變成了一個(gè)管道式的串聯(lián)的形式,這就是一個(gè)進(jìn)步,這樣就比較好理解,永遠(yuǎn)是一層的關(guān)系,不像之前,一層套一層,hin麻煩,這就是promise牛逼的地方。
注意:promise解決了不是callback的問題,而是解決了callback嵌套的問題。
下面這個(gè)例子是用promise寫的簡(jiǎn)單圖片加載:

function loadImg(src) {
    const p = new Promise((resolve, reject) => {
        const img = document.createElement('img');
        img.onload = () => {
            resolve(img); // resolved
        };
        img.onerror = () => {
            const err = new Error(`圖片加載失敗${src}`);
            reject(err);  // rejected
        };
        img.src = src;
    });
    return p;
}
const url = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1607687820492&di=19aaed2d40d4263b5a97432811ed6379&imgtype=0&src=http%3A%2F%2Fi.17173cdn.com%2F2fhnvk%2FYWxqaGBf%2Fcms3%2FfNTkhSbocptcacd.png';
const p = loadImg(url);
p.then(img => {
    console.log(img.width); // 獲取圖片的寬
}).then(img => {
    console.log(img.height); // 獲取圖片的高
}).catch(err => {
    console.log(err);
})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容