2017-12-19 142 views
5

Tôi đang cố gắng sử dụng async/await nhưng tôi nghĩ rằng tôi đang hiểu nhầm điều gì đó nghiêm túc.Sử dụng async/await để lấy dữ liệu từ một cuộc gọi lại và trả lại giá trị chỉ sau khi lời hứa được giải quyết

Về cơ bản nhất có thể, tôi đang cố gắng tính toán khoảng cách giữa danh sách vị trí và một vị trí được chỉ định bằng cách sử dụng bản đồ google api.

Dưới đây là một ví dụ thô về những gì tôi đang cố gắng để làm: https://jsfiddle.net/qu5y69rj/1/

Bạn có thể thấy rằng kết quả của chức năng đó là undefined 3 lần thay vì những gì tôi mong đợi đó sẽ là {distance: "ZERO_RESULTS"} cho mỗi cuộc gọi trong trường hợp của ví dụ giả tạo của tôi.

getDistance = async (start, end) => { 
    const origin = new google.maps.LatLng(start[0], start[1]); 
    const final = new google.maps.LatLng(end[0], end[1]); 
    const service = new google.maps.DistanceMatrixService(); 
    let result; //need to return this value! 
    await service.getDistanceMatrix(
    { 
     origins: [origin], 
     destinations: [final], 
     travelMode: 'DRIVING' 
    }, (response, status) => { 
     if(status === 'OK') result = {distance: response.rows[0].elements[0].status} 
    } 
) 
    return result; 
} 

Tại sao kết quả được trả lại trước khi lời hứa được giải quyết? Làm thế nào tôi có thể trả lại giá trị của result chỉ sau khi lời hứa đó được giải quyết? Đó là sự hiểu biết của tôi rằng bằng cách nói với javascript để chờ đợi, tôi đang nói không di chuyển về phía trước cho đến khi lời hứa này đã được giải quyết. Điều đó có đúng không? Tôi khá bối rối và điều này khiến tôi kéo tóc ra. Bất kỳ trợ giúp được đánh giá cao.

+3

async/chờ đợi chỉ kết thúc tốt đẹp hứa hẹn. Tôi không thấy lời hứa nào trong đoạn mã này. Có phải 'service.getDistanceMatrix' là mã của bạn không? Bạn có thể làm cho nó trở lại một lời hứa chứ không phải là một cuộc gọi lại? –

+0

không có nó là một phần của bản đồ google api vì vậy nó là những gì nó là –

+2

Bạn không thể 'chờ đợi' một chức năng không đồng bộ kiểu gọi lại. Trước tiên, bạn nên tìm hiểu [cách sử dụng lời hứa] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) trước khi cố gắng giải quyết ['async'/'await'] (https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function). –

Trả lời

2

service.getDistanceMatrix chấp nhận gọi lại có nghĩa là ti rất có thể không trả lời lời hứa.

Tuy nhiên, các chức năng không đồng bộ mong đợi lời hứa.

Như một sửa chữa, bạn có thể quấn getDistanceMatrix nó trong một lời hứa (hoặc sử dụng một phương pháp mà trả về một lời hứa):

const getDistanceMatrix = (service, data) => new Promise((resolve, reject) => { 
    service.getDistanceMatrix(data, (response, status) => { 
    if(status === 'OK') { 
     resolve(response) 
    } else { 
     reject(response); 
    } 
    }) 
}); 

getDistance = async (start, end) => { 
    const origin = new google.maps.LatLng(start[0], start[1]); 
    const final = new google.maps.LatLng(end[0], end[1]); 
    const service = new google.maps.DistanceMatrixService(); 
    const result = await getDistanceMatrix(
    service, 
    { 
     origins: [origin], 
     destinations: [final], 
     travelMode: 'DRIVING' 
    } 
) 
    return { 
    distance: result.rows[0].elements[0].status 
    }; 
}; 
+2

tuyệt vời này hoạt động như một sự quyến rũ! Vì vậy, chỉ vì vậy tôi rõ ràng về điều này, tôi có thể gọi là 'chờ đợi' trên lời hứa trong một chức năng tôi tuyên bố là 'async'? và gọi 'await' không "tạm dừng" mã cho đến khi lời hứa được giải quyết/bị từ chối? –

+2

Yessir, đúng vậy – nem035

2

Có ba cách để làm hoạt động async với JavaScript:

  1. Gọi lại: Một hàm chấp nhận gọi lại làm đối số cuối cùng của hàm. Nó trả về không có gì (undefined), và khi hoạt động async hoàn thành, gọi lại được gọi.
  2. Lời hứa: Hàm trả về lời hứa, giải quyết kết quả của thao tác không đồng bộ khi hoàn thành.
  3. Async/Await: Hàm trả về lời hứa và có thể sử dụng từ khóa async để nhận giá trị của các hoạt động không đồng bộ bên trong định nghĩa của nó. Bất cứ điều gì được trả lại bằng cách sử dụng từ khóa return sẽ được bao bọc trong một lời hứa.

Kể từ khi getDistanceMatrix chấp nhận gọi lại, không trả lại gì. Từ khóa await được sử dụng trong mã không cần phải đợi; nó ngay lập tức nhận được giá trị undefined được trả về bởi getDistanceMatrix. Khi hoạt động hoàn thành và gọi lại được gọi là, getDistance đã thực hiện và trả lại kết thúc lâu.

Bạn cần phải quấn getDistanceMatrix để nó trả về một lời hứa, hãy getAllDistance() trở lại một lời hứa là tốt, và đang chờ đợi lời hứa trong bản Tuyên Bố console.log() của bạn:

const coords = [ 
    ['-36.22967', '-125.80271'], 
    ['54.06395', '54.06395'], 
    ['-5.00263', '-137.92806'] 
]; 

function getDistance (start, end) { 
    const origin = new google.maps.LatLng(start[0], start[1]); 
    const final = new google.maps.LatLng(end[0], end[1]); 
    const service = new google.maps.DistanceMatrixService(); 

    return new Promise((resolve, reject) => { 
    service.getDistanceMatrix(
    { 
     origins: [origin], 
     destinations: [final], 
     travelMode: 'DRIVING' 
    }, (response, status) => { 
     if(status === 'OK') { 
     resolve({ distance: response.rows[0].elements[0].status }); 
     } else { 
     reject(new Error('Not OK')); 
     } 
    } 
); 
    }); 
} 

function getAllDistance (starts, end) { 
    const promisedDistances = starts.map((start) => getDistance(start, end)); 
    // Promise.all turns an array of promises into a promise 
    // that resolves to an array. 
    return Promise.all(promisedDistances); 
} 

getAllDistance(coords, ['-30.23978', '-161.31203']) 
    .then(result => { console.log(result); }); 
Các vấn đề liên quan