成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

什么是 Promise

KnewOne / 1295人閱讀

摘要:引言錯(cuò)誤理解精心組織起來的異步代碼還不如使用一團(tuán)亂麻的回調(diào)函數(shù)。但是決議后,可以一直保留著這個(gè)結(jié)果,通過形式添加的回調(diào)函數(shù),甚至在異步操作完成之后才添加的回調(diào)函數(shù),都會(huì)被執(zhí)行調(diào)用。

引言
錯(cuò)誤理解精心組織起來的異步代碼還不如使用一團(tuán)亂麻的回調(diào)函數(shù)。

在處理異步的問題上,回調(diào)基本上能夠勝任,不過這都是建立在一切正常運(yùn)轉(zhuǎn)的基礎(chǔ)上。

然而事與愿違,回調(diào)受到控制反轉(zhuǎn)的影響,把控制權(quán)交給了第三方,這種控制轉(zhuǎn)移導(dǎo)致了一系列的信任問題(回調(diào)調(diào)用過早、回調(diào)調(diào)用過晚、回調(diào)不被調(diào)用、回調(diào)調(diào)用次數(shù)過少或過多等問題)。同時(shí),基于回調(diào)的異步表達(dá)又是無序性的,回調(diào)地獄的使用,讓我們正確理解代碼的難度加大。

函數(shù)的確可以規(guī)避以上的問題,但是,毋庸置疑,這會(huì)再次加大代碼的理解難度。
與其交給不信任的第三方,倒不如轉(zhuǎn)交給一個(gè)位于我們和第三方間的可信任的中介機(jī)制,這里就是我們要說的 Promise

回調(diào)的轉(zhuǎn)變

如何把回調(diào)交給 Promise, 其實(shí)很簡(jiǎn)單。
使用 Promise 后我們就無需再關(guān)心大部分的信任問題和無序性。因?yàn)?Promise 機(jī)制已經(jīng)為我們處理好了,我們不需要寫些特定邏輯來解決一些信任問題和并發(fā)帶來的競(jìng)態(tài)問題,只要我們按照 Promise 規(guī)范正確執(zhí)行即可?,F(xiàn)在,以 setTimeout 代表異步操作來進(jìn)行 Promise 改造。

// callback async
const callback_async = (x = Date.now(), callback) => {
    // do something now
    console.log("callback_async:初始時(shí)間戳", x)
    setTimeout(() => {
        // do something in the future
        let interval = Date.now() - x
        callback && callback(`callback_async:在${interval}毫秒后異步完成`)
    }, 1000)
}
callback_async(undefined, res => {
    console.log("callback_async:", res)
})

Promise 中我們依然能夠看到回調(diào)的身影,只是回調(diào)作為參數(shù)傳遞的位置發(fā)生了變化。我們不再把回調(diào)交給第三方,而是讓 Promise 從第三方獲取某些數(shù)據(jù),然后回調(diào)作為參數(shù)傳遞進(jìn)去。

const promise_async = (x = Date.now()) => {
    return new Promise(resolve => {
        // do something now
        console.log("promise_async:初始時(shí)間戳", x)
        setTimeout(() => {
            // do something in the future
            let interval = Date.now() - x
            resolve(`promise_async:在${interval}毫秒后異步完成`)
        }, 1000)
    })
}
promise_async(undefined).then(res => {
    console.log(res)
})

不同之前的把回調(diào)直接傳給第三方的做法,這次是靠著 Promise 這個(gè)中間機(jī)制來替異步任務(wù)管理著回調(diào)。

錯(cuò)誤的處理

使用 Promise 后,怎么就會(huì)好了很多呢?首先說說在錯(cuò)誤的處理上。
JavaScript 代碼在執(zhí)行的過程中若遇到錯(cuò)誤就不會(huì)執(zhí)行下去的。作為傳入第三方的回調(diào)(同步回調(diào)或異步回調(diào)),如果在此之前就已經(jīng)報(bào)錯(cuò)了,回調(diào)壓根不會(huì)執(zhí)行。在這種情況下,能通過回調(diào)捕獲錯(cuò)誤,也是很有意義的。我們很自然地想到了 try...catch , 不過在異步回調(diào)中,回調(diào)函數(shù)的執(zhí)行棧與原函數(shù)分離開,導(dǎo)致外部是無法抓住異常。不過沒關(guān)系,我們就多捕捉一遍。

在此,我們就用“error-first風(fēng)格”模擬一下。

// callback async
const callback_async = (x = Date.now(), callback) => {
    try {
        console.log("callback_async:初始時(shí)間戳", x)
        // do something now
        // throw "callback-outer: error"
        setTimeout(() => {
            try {
                // do something in the future
                // throw "callback-inner: error"
                let interval = Date.now() - x
                callback && callback(null, `callback_async:在${interval}毫秒后異步完成`)
            } catch (error) {
                callback(error)
            }
        }, 1000)
    } catch (error) {
        callback(error)
    }
}
callback_async(undefined, (error, res) => {
    error?console.log("asyncError:", error):console.log("async:", res)
})

依次解開注釋 throw ... ,我們就可以成功地捕獲到錯(cuò)誤或異常。但同時(shí)也發(fā)現(xiàn),對(duì)于一個(gè)不斷嵌套的異步回調(diào),就回調(diào)地獄那樣,我們會(huì)為每一個(gè)異步回調(diào)做 try...catch 的錯(cuò)誤處理,這會(huì)使原有的代碼更加混亂。

“幸運(yùn)”的是,Promise 已經(jīng)為我們處理好了這個(gè)問題。對(duì)于錯(cuò)誤或異常,我們只需要注冊(cè) rejectedcatch 的回調(diào)即可。不過 Promise 也存在著和上面相同的問題,無法捕獲脫離上下文環(huán)境的錯(cuò)誤或異常,我們只能收到手動(dòng) reject。

const promise_async = (x = Date.now()) => {
    return new Promise((resolve, reject) => {
        // do something now
        // throw "promise-outer: error"
        console.log("promise_async:初始時(shí)間戳", x)
        setTimeout(() => {
            try {
                // do something in the future
                // throw "promise-inner: error"
                let interval = Date.now() - x
                resolve(`promise_async:在${interval}毫秒后異步完成`)
            } catch (error) {
                reject(error)
            }
        }, 1000)
    })
}
promise_async(undefined).catch(error => {
    console.log(error)
})

對(duì)于多個(gè)異步任務(wù),Promise 仍然能夠很好的處理錯(cuò)誤,因?yàn)?Promise 使用的 this-then-that 的流程控制,默認(rèn)處理函數(shù)只是把錯(cuò)誤重新拋出,這使得錯(cuò)誤可以繼續(xù)沿著Promise鏈傳播下去,直到顯式的 rejectedcatch 捕獲錯(cuò)誤。

Promise化

Promise 帶來的好處遠(yuǎn)遠(yuǎn)不止這些。一旦 Promise 決議, 它就永遠(yuǎn)保持這個(gè)狀態(tài),這個(gè) Promise.then(...) 注冊(cè)的回調(diào)就會(huì)被自動(dòng)調(diào)用,且只會(huì)被調(diào)用一次。這也算解決了回調(diào)調(diào)用過少、過多及不被調(diào)用的問題。即使不能解決,但也可以在此基礎(chǔ)上再做處理。你要是問為什么,我只能說人家就是干這個(gè)的,作為一個(gè)可信任的中間協(xié)商機(jī)制。

說到一旦決議就不能改變,這個(gè)很重要么,是的,真的很重要。
在基于回調(diào)模式的異步處理中,JavaScript 代碼執(zhí)行后會(huì)一直走下去,遇到回調(diào)就直接執(zhí)行了。但是 Promise 決議后,可以一直保留著這個(gè)結(jié)果,通過 .then(..) 形式添加的回調(diào)函數(shù),甚至在異步操作完成之后才添加的回調(diào)函數(shù),都會(huì)被執(zhí)行調(diào)用。這也是上一個(gè) Promise 里的錯(cuò)誤只能在 Promise 鏈的下一個(gè)回調(diào)里捕獲的原因。

知道了 Promise 的好處,也知道了基于回調(diào)模式的異步處理方式,我們就可以嘗試把“error-first風(fēng)格”的回調(diào) Promise 化。

// Promise Wrap
var promise_wrap = function(fn){
    return function() {
        let args = Array.from(arguments);
        return new Promise((resolve, reject) => {
            fn.apply(null, args.concat((error, value) => {
                error ? reject(error): resolve(value)
            }))
        })
    }
}

在這里我們可以看到,為了統(tǒng)一處理現(xiàn)在和將來,我們把它們都變成了將來,即所有的操作都成了異步,同步回調(diào)也變成了異步回調(diào)。

JavaScript 異常錯(cuò)誤也是如此,在 Promise 創(chuàng)建過程中或查看決議結(jié)果過程中出現(xiàn)的異常錯(cuò)誤,這個(gè)異常錯(cuò)誤被捕捉都會(huì)變成異步行為。這樣做減少了由函數(shù)順序不確定性(競(jìng)態(tài)條件)帶來的諸多問題。

保持扁平化

從回調(diào)模式跨到 Promise,總會(huì)不小心保留著原來的風(fēng)格,比如嵌套。
Promise 鏈?zhǔn)骄幊套詈帽3直馄交?,不然不就變成另一個(gè)回調(diào)地獄了?關(guān)鍵是還沒有返回或終止 Promise 鏈。

// parallel Promise
var parallel_promise = (x = Date.now()) => {
    Promise.resolve().then(() => {
        new Promise(resolve => {
            setTimeout(() => {
                let interval = Date.now() - x;
                resolve(`parallel-inner:在${interval}毫秒后完成`)
            }, 3000)
        }).then(res => {
            console.log(res)
        })
    }).then(res => {
        let interval = Date.now() - x;
        console.log(`parallel-outer:在${interval}毫秒后完成; res: ${res}`)
    })
}
parallel_promise(undefined)

從上面的執(zhí)行結(jié)果可以看出,parallel-outer 并非在 parallel-inner 后執(zhí)行。這是沒有正確將 Promise 相連接的結(jié)果。

實(shí)際上,這里就是兩個(gè)獨(dú)立競(jìng)爭(zhēng)的 Promise(同時(shí)在執(zhí)行異步任務(wù)而不是一個(gè)接著一個(gè))。同時(shí)我們也會(huì)注意到外層 then(...) 注冊(cè)回調(diào)中 resundefined,因?yàn)閷?duì)于沒有任何顯式的決議,這個(gè)值就是 undefined。

// serial Promise
var serial_promise = (x = Date.now()) => {
    Promise.resolve().then(() => {
        return new Promise(resolve => {
            setTimeout(() => {
                let interval = Date.now() - x;
                resolve(`serial-1:在${interval}毫秒后完成`)
            }, 3000)
        }).then(res => {
            console.log(res)
            return res
        })
    }).then(res => {
        let interval = Date.now() - x;
        console.log(`serial-2:在${interval}毫秒后完成; res: ${res}`)
    })
}
serial_promise(undefined)

所以說,

一個(gè)好的經(jīng)驗(yàn)法則是總是返回或終止Promise鏈,并且一旦得到一個(gè)新的Promise,返回它。
小結(jié)

Promise 來表達(dá)異步和管理并發(fā)無疑是種進(jìn)步,它在程序的順序性和可信任性上提供了自己的解決方案。它不是回調(diào)的替代品,只是幫著異步任務(wù)管理回調(diào)的可信任的中間機(jī)制。

相對(duì)于直接粗暴的回調(diào),Promise 并不會(huì)帶來性能上的提升,但是它會(huì)讓我們的程序更加健壯,也使得代碼更加簡(jiǎn)潔,更加符合我們有序的思維方式。

當(dāng)然,Promise 也有自己的局限性。在并發(fā) Promise.race(...) 上,我們只要第一個(gè)決議即可。當(dāng)出現(xiàn)第一個(gè)決議的 Promise 時(shí),其它的 Promise 就沒有必要進(jìn)行下去了。然而,我們沒把法終止。

在錯(cuò)誤處理上,Promise 鏈中錯(cuò)誤總是由下一個(gè) Promise 捕獲。如果錯(cuò)誤發(fā)生在最后一個(gè) Promise 呢?還有,對(duì)于嵌套的 Promise,內(nèi)部 Promise 已經(jīng)進(jìn)行了錯(cuò)誤處理,但是外部 Promise 卻捕獲不到,這樣真的好么?

Promise 恢復(fù)了可信任性,但我們還想讓異步流程的表達(dá)風(fēng)格更貼近同步的形式,鏈?zhǔn)秸{(diào)用不說不好,只是我們帶著同步操作的慣性。還好,ES6、ES7已經(jīng)給出了方案。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/102352.html

相關(guān)文章

  • Promise之你看得懂的Promise

    摘要:存放成功回調(diào)的函數(shù)存放失敗回調(diào)的函數(shù)監(jiān)聽回調(diào)函數(shù)然后是需要多加一個(gè)狀態(tài)判斷,當(dāng)中是異步操作時(shí),需要在我們之前定義的回調(diào)函數(shù)數(shù)組中添加一個(gè)回調(diào)函數(shù)。參數(shù)函數(shù)返回的對(duì)象,函數(shù)的返回值,最外層的上的和。 本文由作者陳旭鋒(任職網(wǎng)易考拉)授權(quán)網(wǎng)易云社區(qū)發(fā)布。 Promise源碼詳解學(xué)習(xí)知識(shí)要善于思考,思考,再思考。 —— 愛因斯坦 1.回調(diào)地獄曾幾何時(shí),我們的代碼是這樣的,為了拿到回調(diào)的結(jié)果,...

    wwolf 評(píng)論0 收藏0
  • [譯] 深入理解 Promise 五部曲:5. LEGO

    摘要:一個(gè)就像一個(gè)樂高玩具。問題是不是你小時(shí)候玩兒的那個(gè)有趣,它們不是充滿想象力的打氣筒,也不是一種樂高玩具。這是對(duì)的并不是給開發(fā)者使用的,它們是給庫作者使用的。不會(huì)超過這兩種情況。第二個(gè)是根據(jù)第一個(gè)處理函數(shù)如何運(yùn)行來自動(dòng)變成狀態(tài)成功或者失敗。 原文地址:http://blog.getify.com/promis... 在 Part4:擴(kuò)展問題 中,我討論了如何擴(kuò)展和抽象Promise是多么...

    LiveVideoStack 評(píng)論0 收藏0
  • Javascript基礎(chǔ)之-Promise

    摘要:轉(zhuǎn)載自是什么呢根據(jù)的定義是一個(gè)被用于延時(shí)計(jì)算的最終結(jié)果的占位符這個(gè)怎么理解呢比如說,我要去麥當(dāng)勞買點(diǎn)吃的,下單以后人家會(huì)先給你一個(gè)訂單號(hào),等人家外賣做好了,會(huì)提示你,并用那個(gè)訂單小票來換取你真正的食物,在這時(shí)候,那個(gè)訂單小票就是你這頓飯的 轉(zhuǎn)載自: http://www.lht.ren/article/3/ Promise是什么呢?根據(jù)ecma-262的定義: Promise是一個(gè)被用...

    Carson 評(píng)論0 收藏0
  • 在非阻塞IO下的nodejs下的同步并行 ES6的 promise 從入門深入(一)

    摘要:我們先介紹一下中的的一些調(diào)用再結(jié)合的應(yīng)用逐步深入。這就是一些簡(jiǎn)單的的調(diào)用看起來不多,但是靠這個(gè)真得解決了許多必須同步并行的環(huán)境本身是一個(gè)對(duì)象在開始支持。存在兩個(gè)回調(diào)函數(shù)根據(jù)個(gè)人的需求進(jìn)行處理。 什么是promise?為什么要在nodejs中使用promise?使用promise到底有什么好處呢?實(shí)在太多了,一一說來不如直接上實(shí)戰(zhàn)。我們先介紹一下nodejs中的promise的一些調(diào)用....

    luffyZh 評(píng)論0 收藏0
  • JavaScript 異步

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...

    tuniutech 評(píng)論0 收藏0
  • 深入 Promise

    摘要:首先從這個(gè)構(gòu)造函數(shù)說起,它是全局對(duì)象的屬性的值,這也就是為什么瀏覽器環(huán)境下我們能直接調(diào)用它的原因,就像這些構(gòu)造函數(shù)一樣。的產(chǎn)生就是像正常使用構(gòu)造函數(shù)那樣構(gòu)建一個(gè),不過傳給構(gòu)造函數(shù)是內(nèi)部自動(dòng)創(chuàng)建的,作用是把記錄到中。 showImg(https://segmentfault.com/img/bVbgYy2?w=1200&h=600); > new Promise((resolve, re...

    cfanr 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<