小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

JavaScript異步之從promise到await

 Coder編程 2020-02-24

一、從回調(diào)到Promise,為什么要使用它

當(dāng)我們?cè)趫?zhí)行異步任務(wù)的時(shí)候,往往會(huì)使用一個(gè)回調(diào)函數(shù),它會(huì)在異步任務(wù)結(jié)束時(shí)被調(diào)用,它有一個(gè)共同點(diǎn)就是會(huì)在未來被執(zhí)行。例如在node.js中異步讀取文件:

fs.readFile('/etc/passwd', (err, data) => {
  if (err) throw err;
  console.log(data);
});

又如我們寫了個(gè)ajax請(qǐng)求函數(shù):

// 簡化版,請(qǐng)忽略細(xì)節(jié)
const request = function(callback){
  let xhr = new XMLHttpRequest();
   // .....
  xhr.onreadystatechange = function(){
    callback(xhr)              
  }
}
//調(diào)用
request(function(xhr){
  if (xhr.readyState === 4 && xhr.status === 200) {
      // ....
  } else {
      //....
  }  
})

甚至是一個(gè)定時(shí)器任務(wù):

const doSomethingLater = function(delay, callback){
    setTimeout(callback, delay*1000)
}
// 調(diào)用
doSomethingLater(1, function(){
  // .....
})

這樣看使用回調(diào)的方式似乎沒什么問題,但是當(dāng)回調(diào)函數(shù)中又有異步任務(wù)時(shí),就可能出現(xiàn)多層回調(diào),也就是回調(diào)地獄的問題。多層回調(diào)降低了代碼的可讀性和可維護(hù)性。

Promise為我們做了什么

簡單來講,Promise將異步任務(wù)包裝成對(duì)象,將異步任務(wù)完成后要執(zhí)行的函數(shù)傳給then方法,通過resolve來調(diào)用該函數(shù)。如上面定時(shí)器任務(wù)可以改寫成:

const doSomethingLater = function(delay){
    return new Promise((resolve)=>{
      setTimeout(()=>{ resolve() }, delay*1000)
    })
}
doSomethingLater(1)
    .then(()=>{
      console.log('任務(wù)1')
    })

如果定時(shí)任務(wù)中又執(zhí)行定時(shí)任務(wù),就可以這樣寫,而不是再嵌套一層回調(diào):

doSomethingLater(1)
    .then(() => {
        console.log('任務(wù)1')
        return doSomethingLater(1)
    })
    .then(() => {
        console.log('任務(wù)2')
    })

Promise的作用:

  • 把異步任務(wù)完成后的處理函數(shù)換個(gè)位置放:傳給then方法,并支持鏈?zhǔn)秸{(diào)用,避免層層回調(diào)。
  • 捕獲錯(cuò)誤:不管是代碼錯(cuò)誤還是手動(dòng)reject(),都可以用一個(gè)函數(shù)來處理這些錯(cuò)誤。

二、你可能不知道的Promise細(xì)節(jié)

用了Promise就是異步代碼

就算你的代碼原來沒有異步操作:

Promise.resolve()
    .then(() => {
        console.log(1)
    })
console.log(2)
// 2
// 1

這一點(diǎn)可以查一下事件循環(huán)相關(guān)知識(shí)

catch的另一種寫法
Promise.reject('error')
    .then(() => {
    })
    .catch((err) => {
        console.log(err)
    })
// 等價(jià)于
Promise.reject('error')
    .then(() => {
    })
    .then(null, (err) => {
        console.log(err)
    })
// 或者
Promise.reject('error')
    .then(() => {
    }, (err) => {
        console.log(err)
    })

其實(shí)catch只是個(gè)語義化的語法糖,我們也可以直接用then來處理錯(cuò)誤。

then 或 catch 方法始終返回promise對(duì)象

then方法第一個(gè)參數(shù)和第二個(gè)參數(shù)(或catch的參數(shù)),只是調(diào)用條件不同。

Promise.resolve()
    .then(() => {
        return 1
    })
    .then((res) => {
        console.log(res) // 1
    })
    
Promise.resolve()
    .then(() => {
       // 不返回什么
    })
    .then((res) => {
        console.log(res) // undefined,因?yàn)楹瘮?shù)默認(rèn)返回undefined 
    })
   

如果是返回一個(gè)promise對(duì)象:

Promise.resolve()
    .then(() => {
        return new Promise((resolve) => {
            resolve(2)
        })
    })
    .then((res) => {
        console.log(res) // 2, 根據(jù)返回的那個(gè)promise對(duì)象的狀態(tài)來
    })

我們可以通過包裝,使一個(gè)promise對(duì)象的最后狀態(tài)始終是成功的:
例如:

const task = () => {
    return new Promise((resolve, reject) => {
        // ....
    })
}
task()
    .then((res) => {
        console.log(res)
    })
    .catch((err) => {
        console.log(err)
    })

原本調(diào)用task函數(shù)時(shí)需要在外面加一層catch捕獲錯(cuò)誤,其實(shí)可以包裝一下:

const task = () => {
    return new Promise((resolve, reject) => {
        // ....
    })
        .then((res) => {
            return {
                status: 'success',
                value: res
            }
        })
        .catch((err) => {
            return {
                status: 'fail',
                value: err
            }
        })
}
// 現(xiàn)在調(diào)用就會(huì)更簡潔!
task()
    .then((result) => {
        console.log(result)
    })

catch中報(bào)錯(cuò)也可以在后面繼續(xù)捕獲,因?yàn)閏atch也是返回promise對(duì)象嘛

Promise.reject('first error')
    .catch((err) => {
        console.log(err)
        throw new Error('second error')
    })
    .then(null, (err) => {
        console.log(err)
    })

三、await:新的語法糖

await使得異步代碼更像是同步代碼,對(duì)串行的異步調(diào)用寫起來更自然。await后面跟一個(gè)值或promise對(duì)象,如果是一個(gè)值,那么直接返回。如果是一個(gè)promise對(duì)象,則接受promise對(duì)象成功后的返回值?;蛘咴赼wait后面調(diào)用一個(gè)async函數(shù)

const task = async () => {
    return new Promise((resolve, reject) => {
        resolve(1)
    })
}
const handle = async () => {
    let value = await task()
    console.log(value)
}
handle() // 1

使用await要注意錯(cuò)誤的捕獲,因?yàn)閍wait只關(guān)心成功

const task = async () => {
    return new Promise((resolve, reject) => {
        reject(1)
    })
}
const handle = async () => {
    let value = await task()
    console.log(value)
}
handle()

這樣寫會(huì)報(bào)錯(cuò),所以要么在task函數(shù)中捕獲錯(cuò)誤,要么就在task調(diào)用時(shí)捕獲,像這樣:

const task = async () => {
    return new Promise((resolve, reject) => {
        reject(1)
    })
}
const handle = async () => {
    let value = await task().catch((err) => { console.log(err) })
    console.log(value) // undefine, 因?yàn)殄e(cuò)誤處理函數(shù)沒返回值,你也可以返回錯(cuò)誤信息,這樣就會(huì)通過value拿到
}

需要注意的是,使用await也會(huì)使代碼變成異步的:

const handle = async () => {
    let value = await 1
    console.log(value)
}
handle()
console.log(2)
// 2
// 1

完~

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多