Hàm then () có nghĩa là gì trong JavaScript?


Câu trả lời:


348

Cách truyền thống để xử lý các cuộc gọi không đồng bộ trong JavaScript là với các cuộc gọi lại. Giả sử chúng tôi phải thực hiện ba cuộc gọi đến máy chủ, lần lượt từng cuộc gọi để thiết lập ứng dụng của chúng tôi. Với các cuộc gọi lại, mã có thể trông giống như sau (giả sử hàm xhrGET để thực hiện cuộc gọi máy chủ):

// Fetch some server configuration
    xhrGET('/api/server-config', function(config) {
        // Fetch the user information, if he's logged in
        xhrGET('/api/' + config.USER_END_POINT, function(user) {
            // Fetch the items for the user
            xhrGET('/api/' + user.id + '/items', function(items) {
                // Actually display the items here
            });
        });
    });

Trong ví dụ này, trước tiên chúng ta tìm nạp cấu hình máy chủ. Sau đó, dựa vào đó, chúng tôi tìm nạp thông tin về người dùng hiện tại và cuối cùng nhận được danh sách các mục cho người dùng hiện tại. Mỗi cuộc gọi xhrGET có chức năng gọi lại được thực thi khi máy chủ phản hồi.

Bây giờ tất nhiên chúng ta càng có nhiều mức lồng nhau, mã càng khó đọc, gỡ lỗi, bảo trì, nâng cấp và về cơ bản làm việc với. Điều này thường được gọi là địa ngục gọi lại. Ngoài ra, nếu chúng ta cần xử lý lỗi, chúng ta cần chuyển một hàm khác cho mỗi lệnh gọi xhrGET để nói với nó những gì nó cần làm trong trường hợp có lỗi. Nếu chúng tôi muốn chỉ có một trình xử lý lỗi phổ biến, điều đó là không thể.

API Promise được thiết kế để giải quyết vấn đề lồng nhau này và vấn đề xử lý lỗi.

API Promise đề xuất như sau:

  1. Mỗi tác vụ không đồng bộ sẽ trả về một promiseđối tượng.
  2. Mỗi promiseđối tượng sẽ có một thenhàm có thể lấy hai đối số, một hàm success xử lý và một hàm errorxử lý.
  3. Thành công hoặc xử lý lỗi trong thenhàm sẽ chỉ được gọi một lần , sau khi tác vụ không đồng bộ kết thúc.
  4. Các thenchức năng cũng sẽ trở lại một promise, để cho phép chaining nhiều cuộc gọi.
  5. Mỗi trình xử lý (thành công hoặc lỗi) có thể trả về a value, sẽ được chuyển đến hàm tiếp theo dưới dạng một argumentchuỗi trong promises.
  6. Nếu một trình xử lý trả về một promise(thực hiện một yêu cầu không đồng bộ khác), thì trình xử lý tiếp theo (thành công hoặc lỗi) sẽ chỉ được gọi sau khi yêu cầu đó kết thúc.

Vì vậy, mã ví dụ trước có thể dịch sang một cái gì đó như sau, sử dụng lời hứa và $httpdịch vụ (trong AngularJs):

$http.get('/api/server-config').then(
    function(configResponse) {
        return $http.get('/api/' + configResponse.data.USER_END_POINT);
    }
).then(
    function(userResponse) {
        return $http.get('/api/' + userResponse.data.id + '/items');
    }
).then(
    function(itemResponse) {
        // Display items here
    }, 
    function(error) {
        // Common error handling
    }
);

Tuyên truyền thành công và lỗi

Chaining hứa hẹn là một kỹ thuật rất mạnh mẽ cho phép chúng ta thực hiện rất nhiều chức năng, như có một dịch vụ thực hiện cuộc gọi máy chủ, thực hiện một số xử lý hậu kỳ của dữ liệu và sau đó trả lại dữ liệu đã xử lý cho bộ điều khiển. Nhưng khi chúng tôi làm việc với promisecác chuỗi, có một vài điều chúng tôi cần ghi nhớ.

Hãy xem xét promisechuỗi giả thuyết sau với ba lời hứa, P1, P2 và P3. Mỗi người promisecó một trình xử lý thành công và một trình xử lý lỗi, vì vậy S1 và E1 cho P1, S2 và E2 cho P2 và S3 và E3 cho P3:

xhrCall()
  .then(S1, E1) //P1
  .then(S2, E2) //P2
  .then(S3, E3) //P3

Trong dòng chảy thông thường của mọi thứ, khi không có lỗi, ứng dụng sẽ chảy qua S1, S2 và cuối cùng là S3. Nhưng trong cuộc sống thực, mọi thứ không bao giờ suôn sẻ như vậy. P1 có thể gặp lỗi hoặc P2 có thể gặp lỗi, kích hoạt E1 hoặc E2.

Hãy xem xét các trường hợp sau:

• Chúng tôi nhận được phản hồi thành công từ máy chủ trong P1, nhưng dữ liệu được trả về là không chính xác hoặc không có dữ liệu có sẵn trên máy chủ (nghĩ rằng mảng trống). Trong trường hợp như vậy, đối với lời hứa P2 tiếp theo, nó sẽ kích hoạt trình xử lý lỗi E2.

• Chúng tôi nhận được lỗi cho lời hứa P2, kích hoạt E2. Nhưng bên trong trình xử lý, chúng tôi có dữ liệu từ bộ đệm, đảm bảo ứng dụng có thể tải như bình thường. Trong trường hợp đó, chúng tôi có thể muốn đảm bảo rằng sau khi gọi E2, S3.

Vì vậy, mỗi lần chúng ta viết thành công hay xử lý lỗi, chúng ta cần thực hiện một cuộc gọi bằng cách đưa ra chức năng hiện tại của mình, đây có phải là lời hứa thành công hay thất bại cho người xử lý tiếp theo trong chuỗi hứa hẹn không?

Nếu chúng ta muốn kích hoạt trình xử lý thành công cho lời hứa tiếp theo trong chuỗi, chúng ta có thể trả về một giá trị từ thành công hoặc trình xử lý lỗi

Mặt khác, nếu chúng ta muốn kích hoạt trình xử lý lỗi cho lời hứa tiếp theo trong chuỗi, chúng ta có thể thực hiện điều đó bằng cách sử dụng một deferredđối tượng và gọi reject()phương thức của nó

Bây giờ đối tượng trì hoãn là gì?

Các đối tượng bị trì hoãn trong jQuery đại diện cho một đơn vị công việc sẽ được hoàn thành sau này, thường là không đồng bộ. Khi đơn vị công việc hoàn thành, deferredđối tượng có thể được đặt thành giải quyết hoặc thất bại.

Một deferredđối tượng chứa một promiseđối tượng. Thông qua promiseđối tượng, bạn có thể chỉ định những gì sẽ xảy ra khi đơn vị công việc hoàn thành. Bạn làm như vậy bằng cách đặt các hàm gọi lại trên promiseđối tượng.

Các đối tượng bị trì hoãn trong Jquery: https://api.jquery.com/jquery.deferred/

Các đối tượng bị trì hoãn trong AngularJs: https://docs.angularjs.org/api/ng/service/ $ q


3
Viết rất tốt. Điều này đã giúp tôi thực sự hứa hẹn.
Ju66ernaut

Là xử lý lỗi, tham số thứ hai, luôn luôn là tùy chọn?
1,21 gigawatt

Đây là câu trả lời tốt nhất mà tôi đã thấy cho đến nay!
Imam Bux

78

Hàm () có liên quan đến "Lời hứa Javascript" được sử dụng trong một số thư viện hoặc khung như jQuery hoặc AngularJS.

Một lời hứa là một mẫu để xử lý các hoạt động không đồng bộ. Lời hứa cho phép bạn gọi một phương thức gọi là "sau đó" cho phép bạn chỉ định (các) chức năng sẽ sử dụng làm cuộc gọi lại.

Để biết thêm thông tin, hãy xem: http://wildermuth.com/2013/8/3/JavaScript_Promises

Và đối với những lời hứa của Angular: http : // nékaufman.com/blog/2013/09/09/USE- angularjs-promises/


4
Vì vậy, nó giống như một cuộc gọi lại thực thi khi nhiệm vụ được thực hiện? Nó khác biệt như thế nào
Muhammad Umer

3
các Promises JavaScript trong các bình luận khác nói: A promise can only succeed or fail onceIf a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called
Xiao

Ngoài ra, cốm Promise giải thích cách sử dụng promisevà những gì sẽ được thực hiện vớicallback
Xiao

Trên trang đầu tiên, có những đoạn mã bị thiếu (khoảng trắng lớn). Hầu hết mọi người sẽ nghĩ đến việc kiểm tra yếu tố và tìm URL của fiddle bên dưới. Thông báo này dành cho những người còn lại - câu đố vẫn hoạt động;)
DanteTheSmith

1
@MuhammadUmer: đọc stackoverflow.com/a/31453579/1350476 (câu trả lời của Sid)
SharpCoder

32

Theo hiểu biết của tôi, không có một then()phương pháp tích hợp nào javascript(tại thời điểm viết bài này).

Dường như bất cứ điều gì doSome("task")đang trở lại đều có một phương thức được gọi then.

Nếu bạn đăng nhập kết quả trả về của doSome()bàn điều khiển, bạn sẽ có thể thấy các thuộc tính của những gì được trả về.

console.log( myObj.doSome("task") ); // Expand the returned object in the
                                     //   console to see its properties.

CẬP NHẬT (Kể từ ECMAScript6) : -

Các .then()chức năng đã được bao gồm để javascript thuần.

Từ tài liệu Mozilla tại đây ,

Phương thức then () trả về một Promise. Phải có hai đối số: hàm gọi lại cho các trường hợp thành công và thất bại của Lời hứa.

Đối tượng Promise, lần lượt, được định nghĩa là

Đối tượng Promise được sử dụng cho các tính toán hoãn lại và không đồng bộ. Một lời hứa đại diện cho một hoạt động chưa hoàn thành, nhưng dự kiến ​​trong tương lai.

Đó là, các Promisehành vi như một trình giữ chỗ cho một giá trị chưa được tính toán, nhưng sẽ được giải quyết trong tương lai. Và .then()chức năng được sử dụng để liên kết các chức năng sẽ được gọi trên Promise khi nó được giải quyết - là thành công hoặc thất bại.


12
Lúc đó không có tích hợp sẵn .then, nhưng những lời hứa bản địa hiện đang có trong ES6: html5rocks.com/en/tutorials/es6/promises
janfoeh 17/12/13

cảm ơn vì câu trả lời này, tôi đã mong đợi một số cuộc gọi lại hứa hẹn thú vị nhưng hóa ra đó là một chức năng thực tế gọi là 'sau đó' đã được trả về.
spartikus

15

Đây là một điều tôi làm cho bản thân mình để làm rõ mọi thứ hoạt động như thế nào. Tôi đoán những người khác cũng có thể tìm thấy ví dụ cụ thể này hữu ích:

doit().then(function() { log('Now finally done!') });
log('---- But notice where this ends up!');

// For pedagogical reasons I originally wrote the following doit()-function so that 
// it was clear that it is a promise. That way wasn't really a normal way to do 
// it though, and therefore Slikts edited my answer. I therefore now want to remind 
// you here that the return value of the following function is a promise, because 
// it is an async function (every async function returns a promise). 
async function doit() {
  log('Calling someTimeConsumingThing');
  await someTimeConsumingThing();
  log('Ready with someTimeConsumingThing');
}

function someTimeConsumingThing() {
  return new Promise(function(resolve,reject) {
    setTimeout(resolve, 2000);
  })
}

function log(txt) {
  document.getElementById('msg').innerHTML += txt + '<br>'
}
<div id='msg'></div>


5

Đây là một JS_Fiddle nhỏ .

sau đó là một ngăn xếp gọi lại phương thức có sẵn sau khi một lời hứa được giải quyết, nó là một phần của thư viện như jQuery nhưng bây giờ nó có sẵn trong JavaScript gốc và dưới đây là phần giải thích chi tiết về cách thức hoạt động của nó

Bạn có thể thực hiện Lời hứa bằng JavaScript nguyên gốc: giống như có lời hứa trong jQuery, Mọi lời hứa có thể được xếp chồng lên nhau và sau đó có thể được gọi bằng Giải quyết và Từ chối cuộc gọi lại, Đây là cách bạn có thể xâu chuỗi các cuộc gọi không đồng bộ.

Tôi đã rẽ nhánh và Chỉnh sửa từ Tài liệu MSDN về trạng thái sạc pin ..

Những gì nó làm là cố gắng tìm hiểu xem máy tính xách tay hoặc thiết bị của người dùng đang sạc pin. sau đó được gọi và bạn có thể làm bài thành công của bạn.

navigator
    .getBattery()
    .then(function(battery) {
       var charging = battery.charging;
       alert(charging);
    })
    .then(function(){alert("YeoMan : SINGH is King !!");});

Một ví dụ es6 khác

function fetchAsync (url, timeout, onData, onError) {
    
}
let fetchPromised = (url, timeout) => {
    return new Promise((resolve, reject) => {
        fetchAsync(url, timeout, resolve, reject)
    })
}
Promise.all([
    fetchPromised("http://backend/foo.txt", 500),
    fetchPromised("http://backend/bar.txt", 500),
    fetchPromised("http://backend/baz.txt", 500)
]).then((data) => {
    let [ foo, bar, baz ] = data
    console.log(`success: foo=${foo} bar=${bar} baz=${baz}`)
}, (err) => {
    console.log(`error: ${err}`)
})

Định nghĩa :: sau đó là một phương thức được sử dụng để giải quyết các cuộc gọi lại không đồng bộ

điều này được giới thiệu trong ES6

Vui lòng tìm tài liệu phù hợp tại đây Es6 Promising


Câu trả lời của bạn không thực sự trả lời câu hỏi. Nó chỉ cung cấp một ví dụ về việc sử dụng API mà không giải thích thennguồn gốc từ đâu và cách thức hoạt động. Bạn nên cải thiện câu trả lời của bạn để cung cấp những chi tiết đó.
Didier L

@TarandeepSingh - đầu tiên sau đó tuyên bố nơi bạn cảnh báo trạng thái pin không có đối tượng hứa hẹn được trả lại. Vậy thì việc sử dụng thứ hai là gì
Mohit Jain

@MohitJain Nó giới thiệu bạn có thể thực hiện nhiều cuộc gọi lại ngay cả khi bạn không có bất kỳ lời hứa mới nào. Vì, nhiều cuộc gọi cũng có thể được thực hiện với Promise.all.
Tarandeep Singh

WTH có nghĩa là " ngăn xếp gọi lại phương thức "?
Bergi

4

Tôi nghi ngờ doSome trả về cái này, đó là myObj, cũng có một phương thức sau đó. Phương pháp chuẩn chuỗi ...

nếu doSome không trả về cái này, là đối tượng mà doSome được thực thi, hãy yên tâm rằng nó sẽ trả về một số đối tượng bằng phương thức sau đó ...

như @patrick chỉ ra, không có () cho js tiêu chuẩn


1
Tôi nghi ngờ doSome trả lại điều này - không có gì thi hành / biện minh cho những nghi ngờ như vậy
Salathiel Genèse

1

doSome ("tác vụ") phải trả về một đối tượng lời hứa và lời hứa đó luôn có chức năng sau đó. Vì vậy, mã của bạn giống như thế này

promise.then(function(env) {
    // logic
}); 

và bạn biết đây chỉ là một cuộc gọi thông thường đến chức năng thành viên.


1

.then trả về một lời hứa trong chức năng async.

Ví dụ tốt sẽ là:

var doSome = new Promise(function(resolve, reject){
    resolve('I am doing something');
});

doSome.then(function(value){
    console.log(value);
});

Để thêm logic khác vào nó, bạn cũng có thể thêm lệnh reject('I am the rejected param')gọi hàm và console.log nó.


0

Trong trường hợp then()này là một phương thức lớp của đối tượng được trả về bởi doSome()phương thức.


0

Hàm ".then ()" là wideley được sử dụng cho các đối tượng được hứa hẹn trong lập trình Asynchoronus cho Ứng dụng Windows 8 Store. Theo như tôi hiểu thì nó hoạt động theo cách nào đó giống như một cuộc gọi lại.

Tìm chi tiết trong Tài liệu này http://msdn.microsoft.com/en-us/l Library / windows / apps / hh700330.aspx

Nguyên nhân cũng có thể là tên cho bất kỳ chức năng được xác định nào khác.


-1

Một vi dụ khac:

new Promise(function(ok) {
   ok( 
      /* myFunc1(param1, param2, ..) */
   )
}).then(function(){
     /* myFunc1 succeed */
     /* Launch something else */
     /* console.log(whateverparam1) */
     /* myFunc2(whateverparam1, otherparam, ..) */
}).then(function(){
     /* myFunc2 succeed */
     /* Launch something else */
     /* myFunc3(whatever38, ..) */
})

Logic tương tự sử dụng chức năng mũi tên tốc ký:

new Promise((ok) =>
   ok( 
      /* myFunc1(param1, param2, ..) */
)).then(() =>
     /* myFunc1 succeed */
     /* Launch something else */
     /* Only ONE call or statment can be made inside arrow functions */
     /* For example, using console.log here will break everything */
     /* myFunc2(whateverparam1, otherparam, ..) */
).then(() =>
     /* myFunc2 succeed */
     /* Launch something else */
     /* Only ONE call or statment can be made inside arrow functions */
     /* For example, using console.log here will break everything */
     /* myFunc3(whatever38, ..) */
)


-4

Tôi trễ khoảng 8 năm, dù sao thì ... dù sao thì tôi cũng không biết sau đó () làm gì nhưng có lẽ MDN có thể có câu trả lời. Trên thực tế, tôi thực sự có thể hiểu nó nhiều hơn một chút.

Điều này sẽ cho bạn thấy tất cả các thông tin (hy vọng), bạn cần. Trừ khi ai đó đã đăng liên kết này. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

Định dạng là prom.prototype.then () Lời hứa và nguyên mẫu là loại biến giống như biến nhưng không giống biến trong javascript, ý tôi là giống như những thứ khác đến đó như navigator.getBattery (). Then () trong đó cái này thực sự tồn tại nhưng là Hầu như không được sử dụng trên web, ứng dụng này hiển thị trạng thái về pin của thiết bị, thêm thông tin và nhiều thông tin khác về MDN nếu bạn tò mò.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.