#javascript #promise
#javascript #обещание
Вопрос:
В настоящее время у меня есть эта функция, и она работает:
function waitForObjectProperty(object, property) {
return new Promise(function(resolve, reject) {
Object.defineProperty(Object.prototype, property, {
configurable: true,
set: function(value) {
Object.defineProperty(object, property, {
value: value,
});
resolve(object[property]);
},
});
});
}
waitForObjectProperty(window, "google").then(function(object) {
waitForObjectProperty(object, "maps").then(function(object) {
waitForObjectProperty(object, "places").then(function(object) {
console.log('places object:', google.maps.places);
});
});
});
setTimeout(function(){ window.google = {} }, 1000);
setTimeout(function(){ window.google.maps = {} }, 2000);
setTimeout(function(){ window.google.maps.places = {} }, 3000);
.. но мне было интересно, как я могу улучшить это, чтобы мне не приходилось связывать обещания каждый раз, когда мне приходится проверять наличие вложенного объекта?
Комментарии:
1. вы имеете в виду, как
waitForObjectProperty(window, "google") .then(object => waitForObjectProperty(object, "maps")) .then(object => waitForObjectProperty(object, "places")) .then(object =>console.log('places object:', google.maps.places));
2. Можете ли вы использовать синтаксис ES8? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference /…
3.
async/await
намного проще
Ответ №1:
const tapProp = property => object => waitForObjectProperty(object, property);
Promise.resolve(window)
.then(tapProp("google"))
.then(tapProp("maps"))
.then(tapProp("places"))
.then(function(object) {
console.log('places object:', google.maps.places);
});
Комментарии:
1. Разве мне не нужно
bind
передавать дополнительные параметры?2. @3zzy Нет. Этот метод называется
currying
, ведет себя вроде какbind
, но по-другому.
Ответ №2:
Преимущества метода, показанного ниже, в том, что он использует одну строку кода и, что, возможно, более важно, «путь» может быть создан динамически
Краткое объяснение
Путь (после «корня» — window
в вашем случае) представляет собой строку в точечной записи, поэтому сначала разделите эту строку на части
С полученным массивом используйте метод array.reduce, чтобы создать цепочку обещаний — «начальное значение» для array.reduce является Promise.resolve(root)
, и каждое последующее обещание преобразуется (как в вашем коде) в «созданный» объект
Конечно, «вспомогательный» код больше, но конечный результат так же прост, как
waitForNestedObject(window, 'some.very.long.path.that.you.can.even.build.dynamically.if.you.want');
function waitForNestedObject(root, objectPath) {
var waitForObjectProperty = function (object, property) {
return new Promise(function(resolve, reject) {
Object.defineProperty(Object.prototype, property, {
configurable: true,
set: function(value) {
Object.defineProperty(object, property, {
value: value,
});
resolve(object[property]);
},
});
});
}
var steps = objectPath.split('.');
return steps.reduce(function(p, step) {
return p.then(function(object) {
return waitForObjectProperty(object, step);
});
}, Promise.resolve(root));
}
//
// use is simple now
//
waitForNestedObject(window, 'google.maps.places')
.then(function(object) {
console.log(object);
});
setTimeout(function(){ window.google = {} }, 1000);
setTimeout(function(){ window.google.maps = {} }, 2000);
setTimeout(function(){ window.google.maps.places = {hello:'world'} }, 3000);
В современном javascript вы можете написать это следующим образом — (не уверен, почему вы не можете использовать современный javascript (согласно комментарию в другом ответе относительно функций со стрелками))
const waitForNestedObject = (root, objectPath) => {
const waitForObjectProperty = (object, property) => new Promise((resolve, reject) => Object.defineProperty(Object.prototype, property, {
configurable: true,
set: function(value) {
Object.defineProperty(object, property, {
value: value,
});
resolve(object[property]);
},
}));
return objectPath.split('.').reduce((p, step) => p.then(object => waitForObjectProperty(object, step)), Promise.resolve(root));
};
//
// usage remains the same
waitForNestedObject(window, 'google.maps.places')
.then(object => console.log(object));
setTimeout(function(){ window.google = {} }, 1000);
setTimeout(function(){ window.google.maps = {} }, 2000);
setTimeout(function(){ window.google.maps.places = {hello:'world'} }, 3000);
Комментарии:
1. Не могу использовать современный JS, потому что IE11 и нет babel 🙂 Но огромное спасибо за ответ, как раз то, что я искал!
Ответ №3:
function waitForObjectProperty(object, property) {
return new Promise(function(resolve, reject) {
Object.defineProperty(Object.prototype, property, {
configurable: true,
set: function(value) {
Object.defineProperty(object, property, {
value: value,
});
resolve(object[property]);
},
});
});
}
// you can just return promise and then chainning
waitForObjectProperty(window, "google")
.then(object => waitForObjectProperty(object, "maps"))
.then(object => waitForObjectProperty(object, "places"))
.then(object => console.log('places object:', google.maps.places));
setTimeout(function(){ window.google = {} }, 1000);
setTimeout(function(){ window.google.maps = {} }, 2000);
setTimeout(function(){ window.google.maps.places = {} }, 3000);
Комментарии:
1. Это то, что я делаю правильно? Просто не могу использовать функции со стрелками.
2. нет, у вас вложенный .тогда @3zzy — это . затем цепочка — но это не то, что вы имели в виду в вопросе, не так ли