我已经开发JavaScript好几年了,我完全不理解关于承诺的大惊小怪。

似乎我所做的就是改变:

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

代码更多,可读性更差。我在这里没有获得任何东西,它也没有突然神奇地“变平”。更不用说把事情变成承诺了。

那么,承诺有什么好大惊小怪的呢?


当前回答

没有承诺只是回调的包装

例子 你可以在node js中使用javascript原生承诺

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

其他回答

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

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

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

除了上面这些精彩的答案,还可以再加2分:

1. 语义的差异:

应许可能在创世之时就已经解决了。这意味着他们保证条件,而不是事件。如果它们已被解析,则传递给它的已解析函数仍将被调用。

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

2. 控制反转

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

有关解释请参考Javascript事件循环。

对于promise,控制驻留在调用程序中。如果存储promise对象,.then()方法可以在任何时候调用。

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

不,一点也不。

回调函数是JavaScript中的函数,在另一个函数执行完成后,将被调用并执行。那么它是如何发生的呢?

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

承诺只是一种处理和构造异步代码的临时方法,而不是用回调来做同样的事情。

Promise在构造函数中接收两个回调:resolve和reject。承诺中的这些回调为我们提供了对错误处理和成功案例的细粒度控制。当promise执行成功时使用resolve回调,而reject回调用于处理错误情况。

Promises允许程序员编写比使用回调更简单、更易读的代码。


在一个程序中,有一系列的步骤需要执行。

function f() {
   step_a();
   step_b();
   step_c();
   ...
}

每一步之间通常都有信息传递。

function f() {
   const a = step_a(   );
   const b = step_b( a );
   const c = step_c( b );
   ...
}

其中一些步骤可能会花费(相对)较长的时间,所以有时您希望与其他事情并行执行这些步骤。一种方法是使用线程。另一个是异步编程。(这两种方法各有利弊,这里不再讨论。)这里,我们讨论的是异步编程。

在使用异步编程时,实现上述目标的简单方法是提供一个回调函数,在步骤完成时调用它。

// step_* calls the provided function with the returned value once complete.
function f() {
   step_a(
      function( a )
         step_b(
            function( b )
               step_c(
                  ...
               )
            },
         )
      },
   )
}

这很难读懂。承诺提供了一种简化代码的方法。

// step_* returns a promise.
function f() {
   step_a()
   .then( step_b )
   .then( step_c )
   ...
}

返回的对象被称为promise,因为它代表了函数的未来结果(即承诺的结果)(可以是值或异常)。

尽管承诺很有帮助,但使用承诺还是有点复杂。这就是async和await的用武之地。在声明为async的函数中,可以使用await来代替then。

// step_* returns a promise.
async function f()
   const a = await step_a(   );
   const b = await step_b( a );
   const c = await step_c( b );
   ...
}

不可否认,这比使用回调可读性强得多。