Làm thế nào để tôi chờ đợi một lời hứa kết thúc trước khi trả về biến của hàm?


148

Tôi vẫn đang vật lộn với những lời hứa, nhưng đã đạt được một số tiến bộ nhờ vào cộng đồng ở đây.

Tôi có một hàm JS đơn giản truy vấn cơ sở dữ liệu Parse. Nó được cho là trả về mảng kết quả, nhưng rõ ràng do tính chất không đồng bộ của truy vấn (do đó là lời hứa), hàm trả về trước kết quả, để lại cho tôi một mảng không xác định.

Tôi cần làm gì để thực hiện chức năng này chờ kết quả của lời hứa?

Đây là mã của tôi:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    var promise = query.find({
               success: function(results) {
               // results is an array of Parse.Object.
                             console.log(results);
                             //resultsArray = results;
                             return results;
               },

               error: function(error) {
               // error is an instance of Parse.Error.
                             console.log("Error");
               }
    });                           

}

3
Bạn cũng có thể cân nhắc sử dụng async / await. Node hiện hỗ trợ async / await out of the box kể từ phiên bản 7.6
Viliam Simko

Câu trả lời:


66

Thay vì trả về, resultsArraybạn trả lại một lời hứa cho mảng kết quả và sau thenđó trên trang web cuộc gọi - điều này có thêm lợi ích của người gọi khi biết chức năng này đang thực hiện I / O không đồng bộ. Mã hóa đồng thời trong JavaScript dựa trên điều đó - bạn có thể muốn đọc câu hỏi này để có ý tưởng rộng hơn:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    return query.find({});                           

}

// later
resultsByName("Some Name").then(function(results){
    // access results here by chaining to the returned promise
});

Bạn có thể xem thêm các ví dụ về việc sử dụng lời hứa phân tích cú pháp với các truy vấn trong bài đăng trên blog của Parse về nó .


bạn có thể cho tôi biết những gì hỗ trợ của điều này? IE9 hỗ trợ điều này?
sandrina-p

Phải, nhưng bản thân Parse hầu hết đã chết nên có @SandrinaPereira. Đây là mã đám mây phân tích .
Benjamin Gruenbaum

1
Ah, vậy đây không chỉ là javascript thuần túy sao? Tôi đang tìm cách để làm điều này (đợi một chức năng kết thúc để bắt đầu một cái khác) nhưng chỉ với javascript thuần túy ..
sandrina-p

Câu hỏi là về mã phân tích, không hứa hẹn. Hứa hẹn có thể hoạt động (với một thư viện) trong bất kỳ trình duyệt nào. Bluebird chạy trong IE6 và Netscape 7.
Benjamin Gruenbaum

1
Tôi đã đọc SO được hai ngày và vẫn chưa có ai giải quyết vấn đề này. Câu trả lời được chấp nhận này là giống như mọi khác. Hàm trả về một Promise, không phải là giá trị như OP yêu cầu. Tại sao câu trả lời này được đánh dấu là chấp nhận?
iGanja

19

Tôi cần làm gì để thực hiện chức năng này chờ kết quả của lời hứa?

Sử dụng async/await(KHÔNG phải là một phần của ECMA6, nhưng có sẵn cho Chrome, Edge, Firefox và Safari kể từ cuối năm 2017, xem canIuse )
MDN

    async function waitForPromise() {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }

Đã thêm do nhận xét: Hàm async luôn trả về một Promise và trong TypeScript, nó sẽ trông như sau:

    async function waitForPromise(): Promise<string> {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }

4
Hàm async vẫn sẽ trả về một đối tượng lời hứa nếu được gọi mà không có sự chờ đợi (hoặc trong mã không đồng bộ). Kiểm tra kết quả của console.log (WaitForPromise ()) nếu bạn không chắc chắn. Việc kiểm tra console.log (kết quả) trong chức năng async sẽ in ra những gì bạn mong đợi, nhưng việc trả về từ chức năng async xảy ra ngay lập tức mà không chặn và trả lại lời hứa. Chặn trong javascript thường rất tệ vì đây là một ứng dụng đơn luồng và chặn sẽ bỏ đói bất kỳ ứng dụng khách / quán rượu nào khác về cơ bản đưa toàn bộ ứng dụng đến đầu gối.
SRM

1
.net có .wait () trên "nhiệm vụ" như lớp nhiệm vụ. Javascript có thiếu tính năng này không? Tôi cần đợi một cái gì đó trước khi thoát khỏi công cụ dòng lệnh nút có thể chuyển đầu ra của nó sang một công cụ khác. "Chờ đợi" chỉ hoạt động bên trong các chức năng không đồng bộ. Có nghĩa là nó không hoạt động ngoài phạm vi của một lời hứa.
TamusJRoyce

@SRM Tôi cảm thấy như nhận xét của bạn dựa trên việc diễn giải sai mẫu - đó là về Promise.resolve "bên trong" (như ví dụ Promise đơn giản nhất) vì vậy không có người gọi bên ngoài như bạn đang nêu trong nhận xét của mình. Vì vậy, tôi quyết định cập nhật câu trả lời.
Martin Meeser

@TamusJRoyce Đoán đó là một câu hỏi riêng nhưng tôi nghĩ trong C # bạn có thể sử dụng Task.CContueWith (Nhiệm vụ), đó là ý tưởng giống như bạn thấy trong câu trả lời được chấp nhận (nơi nó được gọi là "then ()").
Martin Meeser

Tôi nghĩ rằng tôi thấy bây giờ. Tôi có thể bao bọc toàn bộ tập lệnh của mình trong một hàm async lớn. Và gọi chức năng đó là dòng cuối cùng của kịch bản của tôi. Chức năng đó vẫn sẽ là một chút của tấm nồi hơi. Nhưng cách ít hơn tôi nhận thấy trước đây. Tôi không quen viết các hàm trong các hàm. Cảm ơn bạn @MartinMeeser!
TamusJRoyce

3

Bạn không muốn làm cho hàm chờ, vì JavaScript được dự định là không chặn. Thay vì trả lại lời hứa ở cuối hàm, thì hàm gọi có thể sử dụng lời hứa để nhận phản hồi của máy chủ.

var promise = query.find(); 
return promise; 

//Or return query.find(); 

1
Toàn bộ cuộc gọi lại của bạn với success:bit là tắt.
Benjamin Gruenbaum

Hoặc tốt hơn : return query.find();.
mash

Cũng ok. Tôi sẽ chỉ để nó như thế này cho mục đích minh họa nhưng thêm nó dưới dạng bình luận.
Truy tìm

Tôi đã thử điều này nhưng kết quả dường như không xác định. resultsByName ("name"). then (function (results) {console.log ("got mảng" + results.count);});
mac_55

1
Cảm ơn, đã có một số loại lỗi trong hàm kết quả. Nó đang làm việc bây giờ. Tôi đã thay đổi console.log của mình thành results.length và có thể thấy rằng có 1 mục trong mảng được trả về của tôi :)
mac_55

2

Bạn không thực sự sử dụng lời hứa ở đây. Phân tích cú pháp cho phép bạn sử dụng các cuộc gọi lại hoặc lời hứa; lựa chọn của bạn.

Để sử dụng lời hứa, hãy làm như sau:

query.find().then(function() {
    console.log("success!");
}, function() {
    console.log("error");
});

Bây giờ, để thực thi công cụ sau khi lời hứa hoàn thành, bạn có thể thực hiện nó bên trong cuộc gọi lại lời hứa bên trong then()cuộc gọi. Cho đến nay điều này sẽ giống hệt như các cuộc gọi lại thông thường.

Để thực sự sử dụng tốt các lời hứa là khi bạn xâu chuỗi chúng, như thế này:

query.find().then(function() {
    console.log("success!");

    return new Parse.Query(Obj).get("sOmE_oBjEcT");
}, function() {
    console.log("error");
}).then(function() {
    console.log("success on second callback!");
}, function() {
    console.log("error on second callback");
});

Loại đối tượng nào là đối tượng kết quả? vì nó dường như không chứa mảng của tôi
mac_55

Nó phải là một mảng của Parse.Object.
mash
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.