在node.js中嵌套的promises是否正常?

Gri*_*rim 58 javascript node.js promise

在学习node.js时,我一直在努力解决两周的问题是如何使用node进行同步编程.我发现无论我如何按顺序做事,我总是以嵌套的承诺结束.我发现有一些模块如Q可以帮助保证链的承诺链.

做研究时我不明白的是Promise.all(),Promise.resolve()Promise.reject().Promise.reject通过名称几乎可以自我解释但是在编写应用程序时,我很困惑如何在不破坏应用程序行为的情况下将任何这些包含在函数或对象中.

当来自Java或C#等编程语言时,node.js肯定存在学习曲线.仍然存在的问题是如果promise.js中的promise链接是正常的(最佳实践).

例:

driver.get('https://website.com/login').then(function () {
    loginPage.login('company.admin', 'password').then(function () {
        var employeePage = new EmployeePage(driver.getDriver());

        employeePage.clickAddEmployee().then(function() {
            setTimeout(function() {
                var addEmployeeForm = new AddEmployeeForm(driver.getDriver());

                addEmployeeForm.insertUserName(employee.username).then(function() {
                    addEmployeeForm.insertFirstName(employee.firstName).then(function() {
                        addEmployeeForm.insertLastName(employee.lastName).then(function() {
                            addEmployeeForm.clickCreateEmployee().then(function() {
                                employeePage.searchEmployee(employee);
                            });
                        });
                    });
                });
            }, 750);
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

Tat*_*ton 94

不,Promises的一大优势是你可以保持你的异步代码是线性的而不是嵌套的(来自继续传递样式的回调地狱).

Promise为您提供返回语句和错误抛出,您将通过延续传递方式丢失.

您需要从异步函数返回promise,以便链接返回的值.

这是一个例子:

driver.get('https://website.com/login')
  .then(function() {
    return loginPage.login('company.admin', 'password')
  })
  .then(function() {
    var employeePage = new EmployeePage(driver.getDriver());
    return employeePage.clickAddEmployee();
  })
  .then(function() {
    setTimeout(function() {
      var addEmployeeForm = new AddEmployeeForm(driver.getDriver());

      addEmployeeForm.insertUserName(employee.username)
        .then(function() {
          return addEmployeeForm.insertFirstName(employee.firstName)
        })
        .then(function() {
          return addEmployeeForm.insertLastName(employee.lastName)
        })
        .then(function() {
          return addEmployeeForm.clickCreateEmployee()
        })
        .then(function() {
          return employeePage.searchEmployee(employee)
        });
    }, 750);
});
Run Code Online (Sandbox Code Playgroud)

Promise.all获取一系列承诺并在所有承诺解析后解析,如果有任何拒绝,则拒绝该阵列.这允许您同时执行异步代码而不是串行执行异步代码,并且仍然等待所有并发函数的结果.如果您对线程模型感到满意,请考虑生成线程然后加入.

例:

addEmployeeForm.insertUserName(employee.username)
    .then(function() {
        // these two functions will be invoked immediately and resolve concurrently
        return Promise.all([
            addEmployeeForm.insertFirstName(employee.firstName),
            addEmployeeForm.insertLastName(employee.lastName)
        ])
    })
    // this will be invoked after both insertFirstName and insertLastName have succeeded
    .then(function() {
        return addEmployeeForm.clickCreateEmployee()
    })
    .then(function() {
        return employeePage.searchEmployee(employee)
    })
    // if an error arises anywhere in the chain this function will be invoked
    .catch(function(err){
        console.log(err)
    });
Run Code Online (Sandbox Code Playgroud)

Promise.resolve()并且Promise.reject()是创建时使用的方法Promise.它们用于使用回调包装异步函数,以便您可以使用Promises而不是回调.

Resolve将解决/履行承诺(这意味着then将使用结果值调用链式方法).
拒绝将拒绝承诺(这意味着then将不会调用任何链式方法,但catch将使用出现的错误调用第一个链式方法).

我离开你setTimeout的位置来保存你的程序行为,但这可能是不必要的.


Tha*_*var 8

使用async库和使用async.series而不是嵌套链接,看起来非常难看,难以调试/理解.

async.series([
    methodOne,
    methodTwo
], function (err, results) {
    // Here, results is the value from each function
    console.log(results);
});
Run Code Online (Sandbox Code Playgroud)

Promise.all(iterable)方法返回一个promise,该promise在迭代参数中的所有promise都已解析时解析,或者拒绝第一个传递的拒绝的promise.

var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, "foo");
}); 

Promise.all([p1, p2, p3]).then(function(values) { 
  console.log(values); // [3, 1337, "foo"] 
});
Run Code Online (Sandbox Code Playgroud)

Promise.resolve(value)方法返回一个使用给定值解析的Promise对象.如果该值是一个可设置的(即具有then方法),则返回的promise将"跟随"那个可能的,采用其最终状态; 否则返回的承诺将通过该值来实现.

var p = Promise.resolve([1,2,3]);
p.then(function(v) {
  console.log(v[0]); // 1
});
Run Code Online (Sandbox Code Playgroud)

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

  • 这里没有理由使用`async`库来避免嵌套.OP可以在没有嵌套的情况下链接其承诺调用. (5认同)
  • @CharlesSexton - 一旦你学会了如何使用promises并习惯于异步操作的增强错误处理和异步操作的一般易管理性,你永远不会想要编写异步代码而没有它,我没有找到任何异步库提供的功能不能像Bluebird promise库(我使用的那样)那样容易或更容易地完成.我没有使用异步库,因为我没有找到理由一旦我学会了承诺. (2认同)