不只承諾回調嗎?

本文翻譯自:Aren't promises just callbacks?

I've been developing JavaScript for a few years and I don't understand the fuss about promises at all. 我已經開發JavaScript幾年了,我完全不瞭解關於promise的麻煩。

It seems like all I do is change: 看來我所做的就是改變:

api(function(result){
    api2(function(result2){
        api3(function(result3){
             // do work
        });
    });
});

Which I could use a library like async for anyway, with something like: 無論如何我都可以使用像async這樣的庫,它有類似以下內容:

api().then(function(result){
     api2().then(function(result2){
          api3().then(function(result3){
               // do work
          });
     });
});

Which is more code and less readable. 哪個代碼更多,可讀性更差。 I didn't gain anything here, it's not suddenly magically 'flat' either. 我在這裏什麼都沒得到,也不是突然變得神奇地“平坦”。 Not to mention having to convert things to promises. 更不用說必須將事情變成諾言。

So, what's the big fuss about promises here? 那麼,這裏的諾言有什麼大驚小怪的呢?


#1樓

參考:https://stackoom.com/question/1WZdP/不只承諾回調嗎


#2樓

Promises are not callbacks. 承諾不是回調。 A promise represents the future result of an asynchronous operation . 許諾代表異步操作未來結果 Of course, writing them the way you do, you get little benefit. 當然,以您的方式編寫它們,您會獲得很少的收益。 But if you write them the way they are meant to be used, you can write asynchronous code in a way that resembles synchronous code and is much more easy to follow: 但是,如果按照使用它們的方式來編寫它們,則可以以類似於同步代碼的方式編寫異步代碼,並且更容易遵循:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
});

Certainly, not much less code, but much more readable. 當然,代碼不會太多,但可讀性會更高。

But this is not the end. 但這還沒有結束。 Let's discover the true benefits: What if you wanted to check for any error in any of the steps? 讓我們發現真正的好處:如果您想檢查任何步驟中的任何錯誤怎麼辦? It would be hell to do it with callbacks, but with promises, is a piece of cake: 用回調來做到這一點將是一件令人頭疼的事,但是使用promise卻是小菜一碟:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
});

Pretty much the same as a try { ... } catch block. try { ... } catch塊幾乎相同。

Even better: 更好的是:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
}).then(function() {
     //do something whether there was an error or not
     //like hiding an spinner if you were performing an AJAX request.
});

And even better: What if those 3 calls to api , api2 , api3 could run simultaneously (eg if they were AJAX calls) but you needed to wait for the three? 甚至更好:如果這三個對apiapi2api3可以同時運行(例如,如果它們是AJAX調用),但您需要等待這三個調用怎麼辦? Without promises, you should have to create some sort of counter. 沒有承諾,您應該必須創建某種計數器。 With promises, using the ES6 notation, is another piece of cake and pretty neat: 使用ES6表示法的承諾,是又輕鬆又整潔的事情:

Promise.all([api(), api2(), api3()]).then(function(result) {
    //do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
    //handle the error. At least one of the promises rejected.
});

Hope you see Promises in a new light now. 希望您現在看到一個嶄新的承諾。


#3樓

Yes, Promises are asynchronous callbacks. 是的,Promise是異步回調。 They can't do anything that callbacks can't do, and you face the same problems with asynchrony as with plain callbacks. 他們無法做回調不能做的任何事情,並且異步處理和普通回調一樣面臨同樣的問題。

However, Promises are more than just callbacks. 然而,承諾不僅僅是回調 They are a very mighty abstraction, allow cleaner and better, functional code with less error-prone boilerplate. 它們是非常強大的抽象,它允許更簡潔,更好的功能代碼,並且不易出錯。

So what's the main idea? 那麼主要思想是什麼?

Promises are objects representing the result of a single (asynchronous) computation. 承諾是表示單個(異步)計算結果的對象。 They resolve to that result only once. 他們只解決一次該結果 There's a few things what this means: 這意味着幾件事:

Promises implement an observer pattern: 承諾實現觀察者模式:

  • You don't need to know the callbacks that will use the value before the task completes. 您無需在任務完成之前就知道將使用該值的回調。
  • Instead of expecting callbacks as arguments to your functions, you can easily return a Promise object 您可以輕鬆地return Promise對象,而不必將回調作爲函數的參數,
  • The promise will store the value, and you can transparently add a callback whenever you want. Promise將存儲該值,並且您可以在需要時透明地添加回調。 It will be called when the result is available. 結果可用時將調用它。 "Transparency" implies that when you have a promise and add a callback to it, it doesn't make a difference to your code whether the result has arrived yet - the API and contracts are the same, simplifying caching/memoisation a lot. “透明度”表示當您有一個諾言並向其添加回調時,結果是否到來對您的代碼沒有影響-API和協定相同,從而大大簡化了緩存/存儲。
  • You can add multiple callbacks easily 您可以輕鬆添加多個回調

Promises are chainable ( monadic , if you want ): 承諾是可鏈接一元如果你想 ):

  • If you need to transform the value that a promise represents, you map a transform function over the promise and get back a new promise that represents the transformed result. 如果需要轉換promise表示的值,則可以在promise上映射轉換函數,然後獲取代表轉換結果的新promise。 You cannot synchronously get the value to use it somehow, but you can easily lift the transformation in the promise context. 你不能同步獲取的價值以某種方式使用它,但你可以輕鬆舉起的承諾方面的轉型。 No boilerplate callbacks. 沒有樣板回調。
  • If you want to chain two asynchronous tasks, you can use the .then() method. 如果要鏈接兩個異步任務,可以使用.then()方法。 It will take a callback to be called with the first result, and returns a promise for the result of the promise that the callback returns. 它將使用第一個結果來調用回調,併爲該回調返回的承諾的結果返回承諾。

Sounds complicated? 聽起來複雜嗎? Time for a code example. 編寫代碼示例的時間。

var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
    var p2 = api2(); // returning a promise
    return p2; // The result of p2 …
}); // … becomes the result of p3

// So it does not make a difference whether you write
api1().then(function(api1Result) {
    return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
    return api2();
}).then(console.log)

Flattening does not come magically, but you can easily do it. 拼合並不是神奇的方法,但是您可以輕鬆實現。 For your heavily nested example, the (near) equivalent would be 對於您的大量嵌套示例,(接近)等價於

api1().then(api2).then(api3).then(/* do-work-callback */);

If seeing the code of these methods helps understanding, here's a most basic promise lib in a few lines . 如果看這些方法的代碼有助於理解, 以下幾行是最基本的promise lib

What's the big fuss about promises? 關於承諾的大驚小怪是什麼?

The Promise abstraction allows much better composability of functions. Promise抽象允許更好的功能可組合性。 For example, next to then for chaining, the all function creates a promise for the combined result of multiple parallel-waiting promises. 例如, then進行鏈接的all函數將爲多個並行等待的Promise的組合結果創建一個Promise。

Last but not least Promises come with integrated error handling. 最後但並非最不重要的一點是,Promises帶有集成的錯誤處理。 The result of the computation might be that either the promise is fulfilled with a value, or it is rejected with a reason. 計算的結果可能是,要麼承諾滿足了值,也被拒絕 ,理由。 All the composition functions handle this automatically and propagate errors in promise chains, so that you don't need to care about it explicitly everywhere - in contrast to a plain-callback implementation. 與純回調實現相反,所有組合函數都會自動處理此問題並在Promise鏈中傳播錯誤,因此您無需在任何地方顯式地關心它。 In the end, you can add a dedicated error callback for all occurred exceptions. 最後,您可以爲所有發生的異常添加專用的錯誤回調。

Not to mention having to convert things to promises. 更不用說必須將事情變成諾言。

That's quite trivial actually with good promise libraries, see How do I convert an existing callback API to promises? 實際上,對於良好的Promise庫來說,這是微不足道的,請參閱如何將現有的回調API轉換爲Promise?


#4樓

Promises are not callbacks, both are programming idioms that facilitate async programming. 承諾不是回調,它們都是促進異步編程的編程習慣用法。 Using an async/await-style of programming using coroutines or generators that return promises could be considered a 3rd such idiom. 使用使用協程或生成器返回promise的異步/等待式編程可以被認爲是第三個這樣的習慣用法。 A comparison of these idioms across different programming languages (including Javascript) is here: https://github.com/KjellSchubert/promise-future-task 這些習慣用法在不同編程語言(包括Javascript)中的比較在這裏: https : //github.com/KjellSchubert/promise-future-task


#5樓

No promises are just wrapper on callbacks 沒有承諾只是回調的包裝

example You can use javascript native promises with node js 示例您可以將JavaScript原生Promise與Node JS一起使用

my cloud 9 code link : https://ide.c9.io/adx2803/native-promises-in-node

/**
* Created by dixit-lab on 20/6/16.
*/

var express = require('express');
var request = require('request');   //Simplified HTTP request client.


var app = express();

function promisify(url) {
    return new Promise(function (resolve, reject) {
    request.get(url, function (error, response, body) {
    if (!error && response.statusCode == 200) {
        resolve(body);
    }
    else {
        reject(error);
    }
    })
    });
}

//get all the albums of a user who have posted post 100
app.get('/listAlbums', function (req, res) {
//get the post with post id 100
promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {
var obj = JSON.parse(result);
return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums')
})
.catch(function (e) {
    console.log(e);
})
.then(function (result) {
    res.end(result);
}
)

})


var server = app.listen(8081, function () {

var host = server.address().address
var port = server.address().port

console.log("Example app listening at http://%s:%s", host, port)

})


//run webservice on browser : http://localhost:8081/listAlbums

#6樓

In addition to the already established answers, with ES6 arrow functions Promises turn from a modestly shining small blue dwarf straight into a red giant. 除了已經確定的答案,用ES6箭頭功能承諾把從適度閃耀小藍矮入一顆紅巨星。 That is about to collapse into a supernova: 那即將崩潰成超新星:

api().then(result => api2()).then(result2 => api3()).then(result3 => console.log(result3))

As oligofren pointed out, without arguments between api calls you don't need the anonymous wrapper functions at all: 正如oligofren指出的那樣,在api調用之間沒有參數,您根本不需要匿名包裝器函數:

api().then(api2).then(api3).then(r3 => console.log(r3))

And finally, if you want to reach a supermassive black hole level, Promises can be awaited: 最後,如果您想達到超大質量的黑洞水平,可以等待Promises:

async function callApis() {
    let api1Result = await api();
    let api2Result = await api2(api1Result);
    let api3Result = await api3(api2Result);

    return api3Result;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章