最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入探究JS中的異步編程和事件循環(huán)機(jī)制

 更新時(shí)間:2023年05月23日 10:33:06   作者:阿托  
js是單線(xiàn)程事件循環(huán)模型,同步操作與異步操作時(shí)代碼所依賴(lài)的核心機(jī)制,異步行為是為了優(yōu)化因計(jì)算量大而時(shí)間長(zhǎng)的操作,本文詳細(xì)給大家介紹了JS中的異步編程和事件循環(huán)機(jī)制,文中有詳細(xì)的代碼示例,需要的朋友可以參考下

異步編程

js是單線(xiàn)程事件循環(huán)模型,同步操作與異步操作時(shí)代碼所依賴(lài)的核心機(jī)制。異步行為是為了優(yōu)化因計(jì)算量大而時(shí)間長(zhǎng)的操作。

同步:當(dāng)一個(gè)進(jìn)程在執(zhí)行某個(gè)請(qǐng)求時(shí),如果這個(gè)請(qǐng)求需要等待一段時(shí)間才能返回,那么這個(gè)進(jìn)程會(huì)一直等下去,直到請(qǐng)求返回。

異步:當(dāng)一個(gè)進(jìn)程在執(zhí)行某個(gè)請(qǐng)求時(shí),如果這個(gè)請(qǐng)求需要等待一段時(shí)間才能返回,那么這個(gè)進(jìn)程會(huì)直接向下執(zhí)行,不需要等待,當(dāng)消息返回時(shí)再通知進(jìn)程處理。

Promise

Promise的出現(xiàn)主要時(shí)解決之間異步編程使用回調(diào)函數(shù)的回調(diào)地獄的問(wèn)題。

Promise的狀態(tài)

Promise有三種狀態(tài):

  • pending:待定
  • fulfilled:成功
  • rejected:失敗

兩種狀態(tài)變化:

  • pending -> fulfilled:在promise中調(diào)用resolve()函數(shù)會(huì)產(chǎn)生此狀態(tài)轉(zhuǎn)變
  • pending ->rejected:在promise中調(diào)用reject()函數(shù)會(huì)產(chǎn)生此狀態(tài)轉(zhuǎn)變

promise的基本流程

Promise構(gòu)造函數(shù)

用于創(chuàng)建Promise對(duì)象,需要傳入一個(gè)執(zhí)行器函數(shù),函數(shù)中需要帶兩個(gè)參數(shù):resolved,rejected;用于修改Promise的狀態(tài)

let p = new Promise((resolved,rejected)=>{
    console.log(1);
    resolved();
})
// 1
console.log(p); //Promise?{<fulfilled>: undefined}

Promise.prototype.then()

用于定義成功或失敗狀態(tài)的回調(diào)函數(shù),并返回一個(gè)新的Promise。

let p = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
        resolved("ok");
    },1000);
});
p.then(res=>{
    console.log(res);
},err=>{
    console.log(err);
})
// ok
let p = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
        rejected("err");
    },1000);
});
p.then(res=>{
    console.log(res);
},err=>{
    console.log(err);
})
// err

Promise.prototypr.catch()

用于定義失敗的回調(diào),then方法的語(yǔ)法糖,相當(dāng)于.then(undefined,onRejected);

let p = new Promise((resolved,rejected)=>{
    setTimeout(()=>{
        rejected("err");
    },1000);
});
p.then(res=>{
    console.log(res);
}).catch(err=>{
    console.log(err);
})
// err

Promise.resolve()

返回一個(gè)成功或者失敗的Promise;

let p = Promise.resolve("ok"); //Promise?{<fulfilled>: ok}
let p = Promise.resolve(Promise.reject('err')); //Promise?{<rejected>: 'err'}

Promise.all()

返回一個(gè)新的Promise,只有所有的Promise都成功才成功,否則有一個(gè)失敗就返回失敗的promise

let p = Promise.all([
    Promise.resolve(1),
    Promise.resolve(2),
	Promise.resolve()
]) // Promise?{<fulfilled>: [1,2,undefined]} 
let p = Promise.all([
    Promise.reject('err'),
    Promise.resolve(1),
    Promise.resolve(2)
]) // Promise?{<rejected>: 'err'}

Promise.race()

返回一個(gè)新的Promise,第一個(gè)完成的Promise的結(jié)果狀態(tài)就是最終的結(jié)果狀態(tài)。

let p = Promise.race([
    Promise.resolve(1),
    Promise.resolve(2),
	Promise.resolve()
]) // Promise?{<fulfilled>: 1} 
let p = Promise.all([
    Promise.reject('err'),
    Promise.resolve(1),
    Promise.resolve(2)
]) // Promise?{<rejected>: 'err'}

Promise原理實(shí)現(xiàn)

function Promise(excutor){
    const self = this;
    self.status = "pending";
    self.data = undefined;
    self.callbacks = [] // 用來(lái)保存所有待調(diào)用的回調(diào)函數(shù)
    function resolve(value){
        if(self.status !== "pending"){
            return;
        }
        // 改變狀態(tài)
        self.status = "fulfilled";
        self.data = value;
        //  異步調(diào)用回調(diào)函數(shù)
        if(self.callbacks.length > 0){
            setTimeout(()=>{
                self.callbacks.forEach((obj)=>{
                    obj.onResolved();
                })
            })
        }
    }
    function reject(reason){
        if(self.status !== "pending"){
            return;
        }
        // 改變狀態(tài)
        self.status = "rejected";
        self.data = value;
        //  異步調(diào)用回調(diào)函數(shù)
        if(self.callbacks.length > 0){
            setTimeout(()=>{
                self.callbacks.forEach((obj)=>{
                    obj.onRejected();
                })
            })
        }
    }
    // 立即同步調(diào)用執(zhí)行器函數(shù)
    try{
        excutor(resolve,reject);
    }catch(error){
        reject(error);
    }
}
Promise.prototype.then = function(onResolved,onRejected){
    const  self = this;
    onResolved = typeof onResolved === 'function'?onResolved:value=>value;
    onRejected = typeof onResolved === 'function'?onRejected:reason=>{throw reason};
    // 返回promise對(duì)象
    return new Promise((resolve,reject)=>{
        // 執(zhí)行回調(diào)函數(shù)
        function handle(callback){
            try{
                const x = callback(self.data);
                // 如果返回對(duì)象為promise
                if(x instanceof Promise){
                    x.then(resolve,reject);
                }else{
                    resolve(x);
                }
            }catch(err){
                reject(err);
            }
        }
        // 定義回調(diào)之前,狀態(tài)已經(jīng)改變
        if(self.status == 'fulfilled'){
            setTimeout(()=>{
                handle(onResolved);
            })
        }else if(self.status == 'rejected'){
            setTimeout(()=>{
                handle(onRejected);
            })
        }else{
            // 定義回調(diào)之前狀態(tài)還未改變
            self.callbacks.push({
                onResolved(){
                    handle(onResolved);
                },
                onRejected(){
                    handle(onRejected);
                }
            })
        }
    })
}
Promise.prototype.catch = function(onRejected){
    return this.then(undefined,onRejected)
}
Promise.resolve = function(value){
    return new Promise((resolve,reject)=>{
        if(value instanceof Promise){
            value.then(resolve,reject);
        }else{
            resolve(value);
        }
    })
}
Promise.reject = function(reason){
    return new Promise((resolve,reject)=>{
        reject(reason);
    })
}
Promise.all = function(promises){
    return new Promise((resolve,reject)=>{
        let count = 0;
        let plen = promises.length;
        let values = new Array(plen);
        for(let i = 0;i < plen;i++){
            Promise.resolve(promises[i]).then(value=>{
                count++;
                value[i] = value;
                if(count == plen) resolve(values);
            },err=>{
                reject(err);
            })
        }
    })
}
Promise.race = function(promises){
    return new Promise((resolve,reject)=>{
        for(let i = 0;i < promises.length;i++){
            Promise.resolve(promises[i]).then(value=>{
                resolve(value);
            },err=>{
                reject(err);
            })
        }
    })
}

異步函數(shù)async/await

ES8提出使用async和await解決異步結(jié)構(gòu)組織代碼的問(wèn)題

async

async關(guān)鍵字用于聲明異步函數(shù),使用async關(guān)鍵字可以讓函數(shù)具有異步特征,但總體上其代碼仍然時(shí)同步求值。

async function fn1(){
    console.log(1);
}
fn1();
console.log(2);
// 1
// 2

async的返回值是一個(gè)Promise對(duì)象,如果函數(shù)中返回一個(gè)值value,則async則返回Promise.resolve(value);

await

因?yàn)楫惒胶瘮?shù)主要針對(duì)不會(huì)馬上完成的任務(wù),所以自然需要一種暫停和恢復(fù)執(zhí)行的能力。

await關(guān)鍵字必須在異步函數(shù)中使用。

async/await中真正起作用的是await。async關(guān)鍵字,無(wú)論從哪個(gè)方面來(lái)看,都是一個(gè)標(biāo)識(shí)符。異步函數(shù)中不包含await關(guān)鍵字,其執(zhí)行基本上跟普通函數(shù)沒(méi)有區(qū)別。

async function fn(){
    console.log(1);
    let p = await Promise.resolve('ok');
    console.log(p);
    console.log(2);
}
fn();
console.log(3);
// 1
// 3
// ok
// 2

js事件循環(huán)機(jī)制

js運(yùn)行機(jī)制

因?yàn)閖s時(shí)單線(xiàn)程的,在執(zhí)行代碼時(shí),將不同函數(shù)的執(zhí)行上下文壓入棧中來(lái)保證代碼的有序執(zhí)行,在執(zhí)行同步代碼的時(shí)候,如果遇到異步代碼,js并不會(huì)等待其返回結(jié)果,而是將異步代碼交給對(duì)應(yīng)的異步代碼處理線(xiàn)程處理,繼續(xù)執(zhí)行棧中的任務(wù)。

當(dāng)異步事件執(zhí)行完畢之后,再將異步事件對(duì)應(yīng)的對(duì)調(diào)加入異步執(zhí)行隊(duì)列,當(dāng)主棧中的函數(shù)執(zhí)行完畢后,會(huì)從異步執(zhí)行隊(duì)列中選擇任務(wù)來(lái)執(zhí)行。

宏任務(wù)和微任務(wù)

在任務(wù)隊(duì)列中異步回調(diào)分為2中:微任務(wù)和宏任務(wù)。也就是說(shuō)任務(wù)隊(duì)列可以分為兩種:微任務(wù)隊(duì)列和宏任務(wù)隊(duì)列。

宏任務(wù):全局代碼,settimeout/setinterval,UI渲染,

微任務(wù):promise.then,catch,finally,process.nextTick

宏任務(wù)和微任務(wù)的執(zhí)行順序

  • 代碼從開(kāi)始執(zhí)行調(diào)用全局執(zhí)行棧,script標(biāo)簽內(nèi)的代碼做為宏任務(wù)執(zhí)行。

  • 執(zhí)行過(guò)程中同步代碼立即執(zhí)行,異步代碼由異步處理線(xiàn)程處理然后放入任務(wù)隊(duì)列中。

  • 執(zhí)行過(guò)程中同步代碼立即執(zhí)行,異步代碼放入任務(wù)隊(duì)列中。

    • 先看任務(wù)隊(duì)列中的微任務(wù)隊(duì)列是否存在微任務(wù)

      有微任務(wù):執(zhí)行微任務(wù)隊(duì)列中的所有微任務(wù)

      微任務(wù)執(zhí)行過(guò)程中所產(chǎn)生的微任務(wù)放到微任務(wù)隊(duì)列中,繼續(xù)執(zhí)行。

    • 如果沒(méi)微任務(wù),查看是否具有宏任務(wù),有的話(huà)執(zhí)行,沒(méi)有的話(huà)事件輪詢(xún)結(jié)束。

      執(zhí)行過(guò)程中所產(chǎn)生的微任務(wù)放到微任務(wù)隊(duì)列中。

      完成單個(gè)宏任務(wù)之后,執(zhí)行微任務(wù)隊(duì)列中的任務(wù)。

常見(jiàn)面試題

異步編程的實(shí)現(xiàn)方式有哪些

  • 回調(diào)函數(shù):使用回調(diào)函數(shù)的方式的缺點(diǎn)是,是個(gè)回調(diào)函數(shù)嵌套的時(shí)候,會(huì)照成回調(diào)函數(shù)地獄,上下兩層的回調(diào)函數(shù)間的代碼耦合度太高,不利于代碼維護(hù)。
  • promise:使用promise的方式可以嵌套的函數(shù)調(diào)用做為鏈?zhǔn)秸{(diào)用,但是使用這種方法,有時(shí)會(huì)找出多個(gè)then的鏈?zhǔn)秸{(diào)用,可能造成代碼的語(yǔ)義不夠明確。
  • generator:配合yield實(shí)現(xiàn),可以在函數(shù)內(nèi)實(shí)現(xiàn)中斷。
  • async/await:async函數(shù)是generator和promise實(shí)現(xiàn)的一個(gè)自動(dòng)執(zhí)行的語(yǔ)法糖,他內(nèi)部自帶執(zhí)行器,當(dāng)函數(shù)內(nèi)部執(zhí)行到await語(yǔ)句的時(shí)候,如果語(yǔ)句返回promise對(duì)象,那么函數(shù)將會(huì)等待promise對(duì)象的狀態(tài)變?yōu)閞esolve后再基于向下執(zhí)行。因此可以將異步邏輯轉(zhuǎn)化為同步的順序來(lái)寫(xiě),并且這個(gè)函數(shù)可以自動(dòng)執(zhí)行。

如何改變promise的狀態(tài)

  • 調(diào)用resolve(value),pending ->fulfilled
  • 調(diào)用reject(reason),pending ->rejected
  • 拋出異常:如果當(dāng)前時(shí)pending就會(huì)變成rejected

改變promise狀態(tài)和指定回調(diào)函數(shù)誰(shuí)先誰(shuí)后

都有可能,正常情況下是先指定回調(diào)再改變狀態(tài),但也可以先改變狀態(tài)再指定回調(diào)。

什么時(shí)候能得到數(shù)據(jù)?

  • 先指定回調(diào),當(dāng)狀態(tài)發(fā)生改變時(shí),回調(diào)函數(shù)就會(huì)調(diào)用,得到數(shù)據(jù)。
  • 先改變狀態(tài),當(dāng)指定回調(diào)函數(shù)時(shí),回調(diào)函數(shù)就會(huì)調(diào)用,得到數(shù)據(jù)。

promise中改變狀態(tài)和指定回調(diào)函數(shù)時(shí)做了什么事情

在promise內(nèi)部定義了一個(gè)回調(diào)隊(duì)列。

在狀態(tài)改變時(shí),也就是調(diào)用onresolved或者onrejected函數(shù)時(shí),會(huì)執(zhí)行回調(diào)隊(duì)列中的函數(shù)。

當(dāng)指定回調(diào)函數(shù)時(shí),首先會(huì)判斷當(dāng)前的狀態(tài)是否是pending,如果是則將回調(diào)函數(shù)加入回調(diào)隊(duì)列,否則直接執(zhí)行根據(jù)狀態(tài)執(zhí)行onresolved或者onrejected函數(shù)。

這就是為什么無(wú)論是先改變狀態(tài)還是先指定回調(diào)函數(shù),都能得到最終的結(jié)果的原因。

promise.then() 返回的新promise的結(jié)果由什么決定

  • 如果拋出異常,新的promise變?yōu)閞eject,reason為拋出的異常

  • 如果返回的時(shí)非promise的任意值,新promise變?yōu)閒ulfilled,value為返回的值

  • 如果返回promise的時(shí)另一個(gè)promise對(duì)象,此peomise的結(jié)果就會(huì)成為新promise的結(jié)果。

promise異常穿透

  • 當(dāng)使用promise的then鏈?zhǔn)秸{(diào)用時(shí),可以在最后指定失敗的回調(diào)
  • 前面任何操作處理異常都會(huì)傳到最后的回調(diào)中處理

中斷promise鏈

當(dāng)使用promise的then鏈?zhǔn)秸{(diào)用,在中間中斷,不在調(diào)用后面的回調(diào)函數(shù)。

辦法:在回調(diào)函數(shù)中返回一個(gè)pending狀態(tài)的promise對(duì)象

async/await對(duì)比promise的優(yōu)勢(shì)

  • 代碼讀起來(lái)更像同步,Promise雖然擺脫了回調(diào)地獄,但是then方法的鏈?zhǔn)秸{(diào)用也會(huì)帶來(lái)額外的閱讀負(fù)擔(dān)
  • Promise傳遞中間值非常麻煩,而async、await幾乎是同步的寫(xiě)法

Promist.catch后面的.then還會(huì)執(zhí)行嗎

.then回執(zhí)行,因?yàn)閏atch方法返回的還是一個(gè)promise對(duì)象,依然支持鏈?zhǔn)秸{(diào)用。

Promise中,resolve后面的語(yǔ)句是否還會(huì)執(zhí)行?

會(huì)被執(zhí)行。如果不需要執(zhí)行,需要在 resolve 語(yǔ)句前加上 return。

JS為什么是單線(xiàn)程語(yǔ)言

JavaScript的誕生就是為了處理瀏覽器網(wǎng)頁(yè)的交互(DOM操作的處理、UI動(dòng)畫(huà)等), 設(shè)計(jì)成單線(xiàn)程的原因就是不想讓瀏覽器變得太復(fù)雜,因?yàn)槎嗑€(xiàn)程需要共享資源、且有可能修改彼此的運(yùn)行結(jié)果(兩個(gè)線(xiàn)程修改了同一個(gè)DOM節(jié)點(diǎn)就會(huì)產(chǎn)生不必要的麻煩),這對(duì)于一種網(wǎng)頁(yè)腳本語(yǔ)言來(lái)說(shuō)這就太復(fù)雜了。

為了利用多核CPU的計(jì)算能力,HTML5提出Web Worker標(biāo)準(zhǔn),允許JavaScript腳本創(chuàng)建多個(gè)線(xiàn)程,但是子線(xiàn)程完全受主線(xiàn)程控制,且不得操作DOM。所以,這個(gè)新標(biāo)準(zhǔn)并沒(méi)有改變JavaScript單線(xiàn)程的本質(zhì)。

JS是怎么實(shí)現(xiàn)異步異常運(yùn)行的

JavaScript是單線(xiàn)程的,但它所運(yùn)行的宿主環(huán)境—瀏覽器是多線(xiàn)程,瀏覽器提供了各種線(xiàn)程供Event Loop調(diào)度來(lái)協(xié)調(diào)JS單線(xiàn)程運(yùn)行時(shí)不會(huì)阻塞

談一談setInterval的問(wèn)題

setTimeout的作用是每隔一段指定事件執(zhí)行一個(gè)函數(shù),但是這個(gè)執(zhí)行不是真的到了時(shí)間立即執(zhí)行,它真正的作用是每隔一段時(shí)間將事件加入事件隊(duì)列中去,只有當(dāng)當(dāng)前的執(zhí)行棧為空的時(shí)候,才能去從事件隊(duì)列中取出事件執(zhí)行。

所以可能會(huì)出現(xiàn)這樣的情況,就是當(dāng)前執(zhí)行棧執(zhí)行的時(shí)間很長(zhǎng),導(dǎo)致事件隊(duì)列里邊積累多個(gè)定時(shí)器加入的事件,當(dāng)執(zhí)行棧結(jié)束的時(shí)候,這些事件會(huì)依次執(zhí)行,因此就不能到間隔一段時(shí)間執(zhí)行的效果。

正對(duì)這種現(xiàn)象,我們可以使用setTimeout遞歸調(diào)用來(lái)模擬實(shí)現(xiàn)setInterval,這樣就能確保了只有一個(gè)事件結(jié)束,我們才會(huì)觸發(fā)下一個(gè)定時(shí)器事件。

function mySetInterval(fn,delay){
    var timer = {
        flag = true;
    };
    function interval(){
        if(timer.flag){
            fn();
            setTimeout(interval,delay);
        }
    }
    setTimeout(intetval,delay);
    return timer;
}
function myClearInterval(timer){
    timer.flag = false;
}

以上就是深入探究JS中的異步編程和事件循環(huán)機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于JS異步編程和事件循環(huán)機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 如何判斷Javascript對(duì)象是否存在的簡(jiǎn)單實(shí)例

    如何判斷Javascript對(duì)象是否存在的簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)?lái)一篇如何判斷Javascript對(duì)象是否存在的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-05-05
  • js中if語(yǔ)句的幾種優(yōu)化代碼寫(xiě)法

    js中if語(yǔ)句的幾種優(yōu)化代碼寫(xiě)法

    UglifyJS是一個(gè)對(duì)javascript進(jìn)行壓縮和美化的工具,在它的文檔說(shuō)明中,我看到了幾種關(guān)于if語(yǔ)句優(yōu)化的方法。
    2011-03-03
  • 詳解JavaScript之Array.reduce源碼解讀

    詳解JavaScript之Array.reduce源碼解讀

    這篇文章主要介紹了詳解JavaScript之Array.reduce源碼解讀,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 讓瀏覽器崩潰的12行JS代碼(DoS攻擊分析及防御)

    讓瀏覽器崩潰的12行JS代碼(DoS攻擊分析及防御)

    現(xiàn)在有一段12行的JavaScript代碼,可以讓firefox、chrome、safari瀏覽器崩潰,而且還能讓iphone重啟、安卓閃退,本文作者對(duì)于該12行代碼進(jìn)行了分析解讀并且提出了相應(yīng)的防御辦法,歡迎大家一同探討。有需要的朋友們可以參考借鑒。
    2016-10-10
  • JavaScript如何調(diào)用C++模塊中的函數(shù)

    JavaScript如何調(diào)用C++模塊中的函數(shù)

    這篇文章主要給大家介紹了關(guān)于JavaScript如何調(diào)用C++模塊中函數(shù)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-01-01
  • 寶塔面板部署Next.js項(xiàng)目的完整流程及常見(jiàn)問(wèn)題

    寶塔面板部署Next.js項(xiàng)目的完整流程及常見(jiàn)問(wèn)題

    Next.js是一個(gè)基于React的開(kāi)源框架,用于構(gòu)建快速、現(xiàn)代化的Web 應(yīng)用程序,這篇文章主要介紹了寶塔面板部署Next.js項(xiàng)目的完整流程及常見(jiàn)問(wèn)題,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2026-01-01
  • 微信小程序 textarea 層級(jí)過(guò)高問(wèn)題簡(jiǎn)單解決方案

    微信小程序 textarea 層級(jí)過(guò)高問(wèn)題簡(jiǎn)單解決方案

    這篇文章主要介紹了微信小程序 textarea 層級(jí)過(guò)高問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • TypeScript轉(zhuǎn)javaScript的方法示例

    TypeScript轉(zhuǎn)javaScript的方法示例

    本文主要介紹了TypeScript轉(zhuǎn)javaScript的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 詳解微信小程序開(kāi)發(fā)—你期待的分享功能來(lái)了,微信小程序序新增5大功能

    詳解微信小程序開(kāi)發(fā)—你期待的分享功能來(lái)了,微信小程序序新增5大功能

    微信小程序在12月21日發(fā)布了新版本的開(kāi)發(fā)工具,并在官網(wǎng)公布新增分享、模板消息、客服消息、掃一掃、帶參數(shù)二維碼功能。
    2016-12-12
  • 前端性能優(yōu)化之圖片懶加載技術(shù)3種落地實(shí)現(xiàn)方案

    前端性能優(yōu)化之圖片懶加載技術(shù)3種落地實(shí)現(xiàn)方案

    在JavaScript前端開(kāi)發(fā)中,圖片預(yù)加載是一種常用的技術(shù),旨在提升用戶(hù)體驗(yàn),減少頁(yè)面加載時(shí)的等待時(shí)間,這篇文章主要介紹了前端性能優(yōu)化之圖片懶加載技術(shù)3種落地實(shí)現(xiàn)方案的相關(guān)資料,需要的朋友可以參考下
    2026-04-04

最新評(píng)論

台南县| 庄河市| 锦屏县| 五华县| 龙井市| 广灵县| 临澧县| 疏附县| 峡江县| 武威市| 浦北县| 阿拉善盟| 苍南县| 江北区| 铜鼓县| 成安县| 湖口县| 瑞金市| 沈丘县| 乾安县| 克什克腾旗| 鹤庆县| 蕲春县| 盖州市| 白河县| 千阳县| 武陟县| 康乐县| 河北区| 静乐县| 崇礼县| 阳信县| 霍山县| 鱼台县| 探索| 东至县| 卓尼县| 满洲里市| 沅陵县| 清苑县| 大石桥市|