不只承诺回调吗?

2020/09/27 16:01 · javascript ·  · 0评论

我已经开发JavaScript几年了,我完全不了解关于promise的麻烦。

看来我所做的就是改变:

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

无论如何我都可以使用像async这样的库,它有类似以下内容:

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

哪个代码更多,可读性更差。我在这里什么都没得到,也不是突然变得神奇地“平坦”。更不用说必须将事情变成承诺。

那么,这里的诺言有什么大惊小怪的呢?

承诺不是回调。许诺代表异步操作未来结果当然,以您的方式编写它们,您会受益匪浅。但是,如果按照使用它们的方式来编写它们,则可以以类似于同步代码的方式编写异步代码,并且更容易遵循:

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

当然,代码不会少很多,但是可读性更高。

但这还没有结束。让我们发现真正的好处:如果您想检查任何步骤中的任何错误怎么办?用回调来做到这一点将是一件令人头疼的事,但是用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
});

几乎与try { ... } catch街区相同

更好的是:

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.
});

更妙的是:如果这些3调用什么apiapi2api3可以同时运行(例如,如果他们是AJAX调用),但你需要等待三个?没有承诺,您应该必须创建某种计数器。使用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.
});

希望您现在看到一个新的承诺。

是的,Promise是异步回调。他们无法做回调不能做的任何事情,并且异步处理和普通回调一样面临相同的问题。

然而,承诺是不仅仅是回调。它们是非常强大的抽象,它允许更干净,更好的功能代码,并且不易出错。

那么主要思想是什么?

承诺是表示单个(异步)计算结果的对象。他们只解决一次该结果这意味着几件事:

承诺实现观察者模式:

  • 您无需在任务完成之前就知道将使用该值的回调。
  • 您可以轻松地return实现Promise对象,而不用将回调作为函数的参数
  • Promise将存储该值,并且您可以在需要时透明地添加回调。结果可用时将调用它。“透明度”表示当您有一个诺言并向其添加回调时,结果是否到来对您的代码没有影响-API和协定相同,从而大大简化了缓存/存储。
  • 您可以轻松添加多个回调

承诺是可链接一元如果你想):

  • 如果需要转换promise表示的值,则可以在promise上映射转换函数,然后获取代表转换结果的新promise。你不能同步获取的价值以某种方式使用它,但你可以很容易地解除在承诺方面的转型。没有样板回调。
  • 如果要链接两个异步任务,则可以使用.then()方法。它将使用第一个结果来调用回调,并为回调返回的承诺的结果返回承诺。

听起来复杂吗?编写代码示例的时间。

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)

拼合并不是神奇的方法,但是您可以轻松实现。对于您的大量嵌套示例,(接近)等价于

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

如果看这些方法的代码有助于理解,这里是几行中最基本的promise lib

关于承诺的大惊小怪是什么?

Promise抽象允许更好的功能组合性。例如,then在链接的旁边all函数为多个并行等待的promise的组合结果创建一个promise。

最后但并非最不重要的一点是,Promises带有集成的错误处理。计算的结果可能是,要么承诺被兑现了价值,或者它拒绝与一个道理。与纯回调实现相反,所有组合函数都会自动处理此问题并在Promise链中传播错误,因此您无需在任何地方显式地关心它。最后,您可以为所有发生的异常添加专用的错误回调。

更不用说必须将事情变成承诺。

实际上,对于良好的Promise库来说,这是微不足道的,请参阅如何将现有的回调API转换为Promise?

除了已经确定的答案,用ES6箭头功能承诺把从适度闪耀小蓝矮成一颗红巨星。那即将崩溃成超新星:

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

正如oligofren指出的那样,在api调用之间没有参数,您根本不需要匿名包装器函数:

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

最后,如果您想达到超大质量的黑洞水平,可以等待Promises:

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

    return api3Result;
}

除了上述真棒答案外,还可以添加2点:

1.语义差异:

创建时可能已经解决了承诺。这意味着它们保证条件而不是事件如果它们已经解决,则传递给它的已解决函数仍将被调用。

相反,回调处理事件。因此,如果您感兴趣的事件发生在注册回调之前,则不会调用该回调。

2.控制权倒置

回调涉及控制反转。当您使用任何API注册回调函数时,JavaScript运行时都会存储该回调函数,并在准备好运行时从事件循环中调用它。

请参阅Javascript事件循环以获取解释。

通过Promises,控制权归调用程序所有。如果我们存储promise对象,则可以随时调用.then()方法

除了其他答案,ES2015语法与promises无缝融合,从而减少了更多样板代码:

// Sequentially:
api1()
  .then(r1 => api2(r1))
  .then(r2 => api3(r2))
  .then(r3 => {
      // Done
  });

// Parallel:
Promise.all([
    api1(),
    api2(),
    api3()
]).then(([r1, r2, r3]) => {
    // Done
});

一点都不。

回调只是JavaScript中的函数,在另一个函数的执行完成之后,这些函数将被调用然后执行。那怎么发生的呢?

实际上,在JavaScript中,函数本身被视为对象,因此,与所有其他对象一样,甚至函数也可以作为参数发送给其他函数人们可以想到的最常见和通用的用例是JavaScript中的setTimeout()函数。

承诺不过是处理和结构化异步代码的一种简易方法,与对回调方法进行处理相比。

Promise在构造函数中收到两个回调:解析和拒绝。promise中的这些回调为我们提供了对错误处理和成功案例的细粒度控制。当成功执行Promise时,将使用resolve回调,并使用reject回调来处理错误情况。

承诺不是回调,两者都是促进异步编程的编程习惯用法。使用使用协程或生成器返回承诺的异步/等待方式的编程可以认为是第三个这样的习惯用法。这些成语在不同编程语言(包括Javascript)中的比较在这里:https : //github.com/KjellSchubert/promise-future-task

没有承诺只是回调的包装

示例您可以将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

JavaScript Promises实际上使用回调函数来确定在Promise被解决或拒绝后该怎么做,因此两者没有本质上的不同。Promises背后的主要思想是采用回调-尤其是嵌套的回调,您想在其中执行某种操作,但它更具可读性。

承诺概述:

在JS中,我们可以将异步操作(例如数据库调用,AJAX调用)包装在promise中。通常,我们希望对检索到的数据运行一些其他逻辑。JS Promise具有处理程序功能,用于处理异步操作的结果。处理程序函数甚至可以在其中包含其他异步操作,这些操作可能依赖于先前异步操作的值。

一个承诺始终具有以下三种状态:

  1. 待定:每一个诺言的开始状态,既未实现也不被拒绝。
  2. 完成:操作成功完成。
  3. 拒绝:操作失败。

可以用一个值解决/履行或拒绝未完成的承诺。然后调用以下将回调作为参数的处理程序方法:

  1. Promise.prototype.then() :当promise被解决时,该函数的回调参数将被调用。
  2. Promise.prototype.catch() :当Promise被拒绝时,将调用此函数的回调参数。

尽管上面的方法技巧获得了回调参数,但它们比仅使用回调要好得多,这里的示例将说明很多:

function createProm(resolveVal, rejectVal) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() > 0.5) {
                console.log("Resolved");
                resolve(resolveVal);
            } else {
                console.log("Rejected");
                reject(rejectVal);
            }
        }, 1000);
    });
}

createProm(1, 2)
    .then((resVal) => {
        console.log(resVal);
        return resVal + 1;
    })
    .then((resVal) => {
        console.log(resVal);
        return resVal + 2;
    })
    .catch((rejectVal) => {
        console.log(rejectVal);
        return rejectVal + 1;
    })
    .then((resVal) => {
        console.log(resVal);
    })
    .finally(() => {
        console.log("Promise done");
    });
  • createProm函数创建一个承诺,该承诺会在1秒后基于随机Nr被解析或拒绝
  • 如果promise被解决,then则调用第一个方法,并将解决的值作为回调的参数传入
  • 如果承诺被拒绝,catch则调用第一个方法,并将拒绝的值作为参数传递
  • catchthen方法返回的承诺,这就是为什么我们可以把它们连。他们在中包装任何返回值,在中包装任何Promise.resolve抛出的值(使用throw关键字)Promise.reject因此,任何返回的值都将转换为一个承诺,并且在这个承诺上我们可以再次调用处理程序函数。
  • 与嵌套回调相比,Promise链为我们提供了更好的控制和更好的概览。例如,该catch方法处理在catch处理程序之前发生的所有错误
本文地址:http://javascript.askforanswer.com/buzhichengnuohuidiaoma.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!